Подтвердить что ты не робот

Какой метод следует использовать для записи сообщений об ошибках в "stderr" с использованием "printf" в bash script?

Я хочу направить вывод printf в bash script на stderr вместо stdout.

Я не, прося о перенаправлении либо stderr, либо stdout, откуда они в настоящее время маршрутизируются. Я просто хочу иметь возможность отправлять выходные данные от printf до stderr, а не по умолчанию stdout.

Я немного экспериментировал и обнаружил, что добавление 1>&2 к printf, как показано в примере ниже, похоже, делает то, что я хочу. Тем не менее, у меня есть нет опыт использования bash. Поэтому мой основной вопрос: есть ли "лучший" способ сделать это в bash?

Под "лучше" я имею в виду, есть ли другой способ сделать это, которое чаще используется, более условно или более идиоматично? Как мог бы сделать это более опытный программист bash?

#!/bin/bash
printf "{%s}   This should go to stderr.\n" "$(date)" 1>&2 
printf "[(%s)] This should go to stdout.\n" "$(date)" 

У меня также есть вторичный вопрос. Я прошу об этом не так много, потому что мне нужно знать, но больше, потому что мне просто любопытно и хотелось бы лучше понять, что происходит.

Кажется, что выше будет работать, только когда он запускается внутри оболочки script. Кажется, он не работает, когда я пытаюсь выполнить его из командной строки.

Вот пример того, что я имею в виду.

[email protected]:~$ printf "{%s} Sent to stderr.\n" "$(date)" 1>&2 2> errors.txt
{Sat Jun  9 14:08:46 EDT 2012} Sent to stderr.
[email protected]:~$ ls -l errors.txt
-rw-rw-r-- 1 irrational irrational 0 Jun  9 14:39 errors.txt

Я бы ожидал, что команда printf выше не будет иметь выхода, потому что выход должен перейти к stderr, который, в свою очередь, должен перейти в файл. Но этого не происходит. А?

4b9b3361

Ответ 1

Во-первых, да, 1>&2 - это правильная вещь.

Во-вторых, причина, по которой ваш пример 1>&2 2>errors.txt не работает, объясняется тем, что именно перенаправляет.

1>&2 означает, что "make filehandle 1 указывает на то, где в настоящее время выполняется файл-дескриптор 2" - т.е. материал, который был бы записан в stdout, теперь переходит в stderr. 2>errors.txt означает "откройте дескриптор файла до errors.txt и сделайте дескриптор файла 2 для него" - т.е. материал, который был бы записан в stderr, теперь переходит в errors.txt. Но filehandle 1 не затрагивается вообще, поэтому материал, написанный на stdout, по-прежнему отправляется в stderr.

Правильная вещь - 2>errors.txt 1>&2, которая сделает записи как stderr, так и stdout перейдите к errors.txt, потому что первая операция будет "открыта errors.txt и сделает stderr point to it", а вторая операция будет "сделать stdout точкой, где stderr указывает сейчас".

Ответ 2

  • Это кажется мне разумным. Вам не нужен 1, хотя - он будет работать как есть, но он подразумевал:

    printf "{%s}   This should go to stderr.\n" "$(date)" >&2 
    
  • У вас есть проблема порядка операций:

    $ printf "{%s} Sent to stderr.\n" "$(date)" 2> errors.txt 1>&2
    $ ls -l errors.txt 
    -rw-r--r--  1 carl  staff  47 Jun  9 11:51 errors.txt
    $ cat errors.txt 
    {Sat Jun  9 11:51:48 PDT 2012} Sent to stderr.
    

Ответ 3

Вопрос, похоже, указывает на некоторую путаницу. Вы не хотите перенаправлять stdout, вы просто хотите, чтобы printf отправил свой вывод в stderr... Но к этому вы должны использовать перенаправление.

Команда printf всегда отправляет нормальный вывод на свой stdout. Это то, что делает printf. Чтобы добиться того, чего вы хотите, вы должны иметь оболочку, которая должна указывать, что stdout временно указывает на то, куда вы хотите, чтобы выход шел. Заметьте, что я говорю временно. Когда вы вводите команду, например

$ printf "Hello World!" >&2

оболочка изменяет дескриптор stdout на время выполнения инструкции printf. Затем оболочка восстанавливает исходное значение stdout перед тем, как продолжить следующую команду. Фактически, если вы хотите перенаправить stdout навсегда, вы используете специальную команду

$ exec >&2

После того, как оболочка выполнила это, оболочка больше не запоминает исходное значение дескриптора stdout.

Ответ 4

Типичными идиомами являются:

echo foo >&2           # you don't need to specify file descriptor 1
echo foo > /dev/stderr # more explicit, but wordier and less portable