Почему в этом сценарии оболочки bourne выполняется `exec 2> & 1`?

Я переношу старый сценарий ksh в оболочку Bourne. Старый скрипт ksh содержит следующий код:

#!/bin/sh tmpLog=/var/tmp/logfile.$$ exec 1> $tmpLog exec 2>&1 eval $* another_command_1 another_command_2 

Из того, что я читал, кажется, что эти два оператора exec предназначены для выполнения $ *, another_command_1, another_command_2 и всех следующих команд; а затем перенаправить все STDERR и STDOUT из этих команд в /var/tmp/logfile.$$ . Однако, когда я запускаю это в скрипте, скрипт выходит из строя после exec 2>&1 .

 stefanl@host:~ $ sh -xv ./output.sh echo "Hello" #!/bin/sh tmpLog=/var/tmp/logfile.$$ + tmpLog=/var/tmp/logfile.39918 exec 1> $tmpLog + exec exec 2>&1 + exec stefanl@host:~ $ 

И когда я запускаю это в командной строке, моя оболочка зависает после выполнения exec 2>&1 :

 stefanl@host:~ $ tmpLog=/var/tmp/logfile.$$ stefanl@host:~ $ exec 1> $tmpLog stefanl@host:~ $ exec 2>&1 ### FREEZE ### 

Мои вопросы:

  1. Что должен делать exec 2>&1 ?
  2. Почему это терпит неудачу для меня?

Ваш скрипт не терпит неудачу – он работает нормально. Ваше понимание верно в том, что exec >logfile; exec 2>&1 exec >logfile; exec 2>&1 перенаправляет как стандартный вывод, так и стандартную ошибку в logfile . Таким образом, вы должны искать в файле журнала, а не на своем терминале для вывода и ошибки. Если вы выполняете эти перенаправления непосредственно в своей текущей оболочке, похоже, что ваша оболочка заблокирована, потому что вы отправили весь вывод от своего терминала.

Обратите внимание, что выход из параметра xtrace ( set -x ) также относится к стандартной ошибке, которая всегда является файловым дескриптором 2 … который вы отправили в файл журнала. Вы должны найти остальную часть после exec 2>&1 .

Эта форма exec (т.е. без команды) используется для перенаправления всего последующего вывода из текущего интерпретатора оболочки.

из встроенной помощи bash:

 $ help exec
 exec: exec [-cl] [-a name] [команда [arguments ...]] [перенаправление ...]
     Замените оболочку данной командой.

     Выполните команду COMMAND, заменив эту оболочку указанной программой.
     Аргументы становятся аргументами КОМАНДЫ.  Если COMMAND не указано,
     любые перенаправления вступают в силу в текущей оболочке.
     [...]

Я использую exec &> logfile для перенаправления stdout и stderr одновременно. например, большинство моих сценариев оболочки резервного копирования и rsync (или любой скрипт, который дает много результатов, которые я могу изучить позже) начинаются с чего-то вроде этого:

 BNAME=$(basename "$0" .sh) LOGFILE="/tmp/$BNAME.log" savelog "$LOGFILE" exec &> "$LOGFILE" 

Затем я запускаю скрипт из cron или в фоновом режиме и использую tail -F для просмотра файла журнала по мере запуска скрипта. Savelog позволяет мне сохранять выходные данные из последних 7 запусков (по умолчанию – savelog -c ).