Это старый вопрос, но одна вещь требует уточнения .
Хотя ответы Карла Норума и Догбена верны, предполагается, что измените сценарий, чтобы он работал .
Я хотел бы отметить, что вам не нужно менять скрипт :
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
Это работает, если вы вызываете его по-другому:
./fdtest 3>&1 4>&1
, что означает перенаправление файловых дескрипторов 3 и 4 на 1 (что является стандартным выводом).
Суть в том, что сценарий отлично подходит для записи в дескрипторы, отличные от 1 и 2 (stdout и stderr) , если эти дескрипторы предоставляются родительским процессом .
Ваш пример на самом деле довольно интересен, поскольку этот скрипт может записывать в 4 разных файла:
./fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
Теперь у вас есть выходные данные в 4 отдельных файлах:
$ for f in file*; do echo $f:; cat $f; done
file1.txt:
This
file2.txt:
is
file3.txt:
a
file4.txt:
test.
Что еще интереснее 1032 *, так это то, что вашей программе не нужно иметь права на запись для этих файлов, потому что она фактически не открывает их.
Например, когда я запускаю sudo -s
, чтобы изменить пользователя на root, создайте каталог с правами root и попробуйте выполнить следующую команду от имени моего обычного пользователя (rsp в моем случае), например:
# su rsp -c '../fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt'
Я получаю ошибку:
bash: file1.txt: Permission denied
Но , если я делаю перенаправление вне su
:
# su rsp -c '../fdtest' >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
(обратите внимание на разницу в одинарных кавычках) это работает и я получаю:
# ls -alp
total 56
drwxr-xr-x 2 root root 4096 Jun 23 15:05 ./
drwxrwxr-x 3 rsp rsp 4096 Jun 23 15:01 ../
-rw-r--r-- 1 root root 5 Jun 23 15:05 file1.txt
-rw-r--r-- 1 root root 39 Jun 23 15:05 file2.txt
-rw-r--r-- 1 root root 2 Jun 23 15:05 file3.txt
-rw-r--r-- 1 root root 6 Jun 23 15:05 file4.txt
, которые являются 4 файлами, принадлежащими root, в каталоге, принадлежащем root - , хотя у сценария не было разрешений на создание этих файлов.
Другим примером будет использование chroot-тюрьмы или контейнера и запуск программы внутри, где у нее не будет доступа к этим файлам, даже если она запускается от имени root и все еще перенаправляет эти дескрипторы извне, где вам нужно, без фактического предоставления доступа к вся файловая система или что-нибудь еще в этом сценарии.
Дело в том, что вы обнаружили очень интересный и полезный механизм . Вам не нужно открывать все файлы внутри вашего скрипта, как было предложено в других ответах. Иногда полезно перенаправить их во время вызова скрипта.
Подводя итог , это:
echo "This"
фактически эквивалентно:
echo "This" >&1
и запуск программы как:
./program >file.txt
совпадает с:
./program 1>file.txt
Число 1 является просто номером по умолчанию и является стандартным.
Но даже эта программа:
#!/bin/bash
echo "This"
может вызвать ошибку "Bad descriptor". Как? При запуске как:
./fdtest2 >&-
Вывод будет:
./fdtest2: line 2: echo: write error: Bad file descriptor
Добавление >&-
(что совпадает с 1>&-
) означает закрытие стандартного вывода. Добавление 2>&-
будет означать закрытие stderr.
Вы даже можете сделать более сложную вещь . Ваш оригинальный скрипт:
#!/bin/bash
echo "This"
echo "is" >&2
echo "a" >&3
echo "test." >&4
при запуске только с:
./fdtest
печать:
This
is
./fdtest: line 4: 3: Bad file descriptor
./fdtest: line 5: 4: Bad file descriptor
Но вы можете заставить работать дескрипторы 3 и 4, но номер 1 не работает, выполнив:
./fdtest 3>&1 4>&1 1>&-
Это выводит:
./fdtest: line 2: echo: write error: Bad file descriptor
is
a
test.
Если вы хотите, чтобы дескрипторы 1 и 2 вышли из строя, запустите его так:
./fdtest 3>&1 4>&1 1>&- 2>&-
Вы получаете:
a
test.
Почему? Ничего не подвело? Это было , но без stderr (дескриптор файла номер 2) вы не видели сообщений об ошибках!
Я думаю, что очень полезно экспериментировать таким образом, чтобы понять, как работают дескрипторы и их перенаправление.
Ваш скрипт действительно очень интересный пример - и я утверждаю, что он вообще не сломан, вы просто неправильно его использовали! :)