чайников - основы bash. часть 2




Что означает «2> & 1» в оболочке? (10)

В оболочке Unix, если я хочу объединить stderr и stdout в поток stdout для дальнейших манипуляций, я могу добавить следующее в конце моей команды:

2>&1

Итак, если я хочу использовать head на выходе из g++ , я могу сделать что-то вроде этого:

g++ lots_of_errors 2>&1 | head

поэтому я вижу только первые несколько ошибок.

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

Может ли кто-то сломать это и объяснить персонажа по характеру, что означает 2>&1 ?


Перенаправление ввода

Перенаправление ввода приводит к тому, что файл, имя которого определяется расширением слова, которое нужно открыть для чтения в дескрипторе файла n, или стандартный ввод (дескриптор файла 0), если n не указано.

Общий формат для перенаправления ввода:

[n]<word

Перенаправление вывода

Перенаправление вывода вызывает файл, имя которого является результатом расширения слова, которое нужно открыть для записи в дескрипторе файла n, или стандартный вывод (дескриптор файла 1), если n не указано. Если файл не существует, он создается; если он существует, он усекается до нулевого размера.

Общий формат для перенаправления вывода:

[n]>word

Перемещение дескрипторов файлов

Оператор перенаправления,

[n]<&digit-

перемещает дескриптор файла в дескриптор файла n или стандартный ввод (дескриптор файла 0), если n не указывается. после дублирования символ n закрывается.

Аналогичным образом оператор перенаправления

[n]>&digit-

перемещает дескриптор файла в дескриптор файла n или стандартный вывод (дескриптор файла 1), если n не указывается.

Ref:

man bash

Введите /^REDIRECT чтобы найти в разделе redirection и узнать больше ...

Онлайн-версия здесь: 3.6 Перенаправления

PS:

Много времени, man был мощным инструментом для изучения Linux.


Некоторые трюки о перенаправлении

Некоторые особенности синтаксиса в этом могут иметь важное поведение. Есть несколько небольших примеров о перенаправлении, порядке STDERR , STDOUT и порядка .

1 - Перезапись или добавление?

Символ > означает перенаправление .

  • > означает отправить в целом завершенный файл , переписывая цель, если она существует (см. функцию noclobber bash на # 3 позже).
  • >> среднем отправить в дополнение к приложению к цели, если она существует.

В любом случае файл будет создан, если он не существует.

2 - Командная строка оболочки зависит от порядка!

Для тестирования этого нам нужна простая команда, которая отправит что-то на оба выхода :

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(Ожидая, что у вас нет каталога с именем /tnt , конечно;). Ну, у нас есть это!

Итак, давайте посмотрим:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

Последняя командная строка сбрасывает STDERR на консоль, и, похоже, это не ожидаемое поведение ... Но ...

Если вы хотите сделать некоторую фильтрацию сообщений об одном выходе, другой или оба:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

Обратите внимание, что последняя строка в этом параграфе точно такая же, как в предыдущем абзаце, где я писал, похоже, не является ожидаемым поведением (так что это может быть даже ожидаемое поведение).

Ну, есть небольшие трюки о перенаправлениях, для выполнения разных операций на обоих выходах :

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

Nota: дескриптор &9 будет возникать спонтанно из-за ) 9>&2 .

Добавление: nota! С новой версией bash ( >4.0 ) появилась новая функция и более сексуальный синтаксис для такого рода вещей:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

И, наконец, для такого каскадного форматирования вывода:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Добавление: nota! Тот же новый синтаксис в обоих направлениях:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Когда STDOUT проходит через определенный фильтр, STDERR к другому, и, наконец, оба выхода, объединенные, проходят через третий командный фильтр.

3 - Слово о опции noclobber и >| синтаксис

Речь идет о перезаписи :

В то время как set -o noclobber инструктирует bash не перезаписывать какой-либо существующий файл, >| синтаксис позволит вам пройти это ограничение:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

Файл перезаписывается каждый раз, ну теперь:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

Пройдите через >| :

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Отсоединение этой опции и / или запрос, если она уже установлена.

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - Последний трюк и многое другое ...

Для перенаправления обоих выходных данных из данной команды мы видим, что правильный синтаксис может быть:

$ ls -ld /tmp /tnt >/dev/null 2>&1

для этого специального случая есть синтаксис ярлыка: &> ... или >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Nota: если существует 2>&1 , 1>&2 является правильным синтаксисом:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Теперь, я позволю вам подумать:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c- Если вас интересует дополнительная информация

Вы можете прочитать точное руководство, нажав:

man -Len -Pless\ +/^REDIRECTION bash

в консоли bash ;-)


2 - стандартная ошибка консоли.

1 - стандартный вывод консоли.

Это стандартный Unix, и Windows также следует за POSIX.

Например, когда вы запускаете

perl test.pl 2>&1

стандартная ошибка перенаправляется на стандартный вывод, поэтому вы можете видеть оба выхода вместе:

perl test.pl > debug.log 2>&1

После выполнения вы можете увидеть весь вывод, включая ошибки, в debug.log.

perl test.pl 1>out.log 2>err.log

Затем стандартный вывод идет в out.log и стандартная ошибка в err.log.

Я предлагаю вам попытаться понять их.


Если /foo не существует в вашей системе и /tmp делает ...

$ ls -l /tmp /foo

распечатает содержимое /tmp и выведет сообщение об ошибке для /foo

$ ls -l /tmp /foo > /dev/null

отправит содержимое /tmp в /dev/null и выведет сообщение об ошибке для /foo

$ ls -l /tmp /foo 1> /dev/null

будет делать то же самое (обратите внимание на 1 )

$ ls -l /tmp /foo 2> /dev/null

распечатает содержимое /tmp и отправит сообщение об ошибке в /dev/null

$ ls -l /tmp /foo 1> /dev/null 2> /dev/null

отправит как листинг, так и сообщение об ошибке в /dev/null

$ ls -l /tmp /foo > /dev/null 2> &1

является сокращением


Номера относятся к дескрипторам файла (fd).

  • Zero - это stdin
  • Один из них
  • Два - это stderr

2>&1 перенаправляет fd 2 в 1.

Это работает для любого количества файловых дескрипторов, если программа их использует.

Вы можете посмотреть /usr/include/unistd.h если вы забудете их:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

Тем не менее, я написал инструменты C, которые используют нестандартные дескрипторы файлов для пользовательского ведения журнала, поэтому вы не видите его, если не перенаправляете его на файл или что-то в этом роде.


С точки зрения программиста это означает именно это:

dup2(1, 2);

См. Справочную страницу .

Понимание того, что 2>&1 является копией, также объясняет, почему ...

command >file 2>&1

... это не то же самое, что ...

command 2>&1 >file

Первый отправит оба потока в file , а второй отправит ошибки в stdout и обычный вывод в file .


Чтобы ответить на ваш вопрос: он принимает любой вывод ошибки (обычно отправляется в stderr) и записывает его на стандартный вывод (stdout).

Это полезно, например, «больше», когда вам нужен пейджинг для всего вывода. Некоторые программы, такие как печать информации об использовании в stderr.

Чтобы помочь вам запомнить

  • 1 = стандартный выход (когда программы печатают нормальный выход)
  • 2 = стандартная ошибка (когда программы печатают ошибки)

«2> & 1» просто указывает все отправленные на stderr, вместо stdout.

Я также рекомендую прочитать этот пост при переадресации ошибок, когда этот вопрос будет рассмотрен полностью.


Эта конструкция отправляет стандартный поток ошибок ( stderr ) в текущее местоположение стандартного вывода ( stdout ) - эта проблема с валютой, по-видимому, игнорировалась другими ответами.

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

Вот некоторые примеры:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

Обратите внимание, что последний не будет перенаправлять stderr на outfile2 - он перенаправляет его на то, что было stdout когда был встречен аргумент ( outfile1 ), а затем перенаправляет stdout в outfile2 .

Это позволяет довольно сложный обман.


Я нашел этот блестящий пост в перенаправлении: все о перенаправлениях

Перенесите как стандартный вывод, так и стандартную ошибку в файл

$ command &> file

Этот однострочный оператор использует оператор &> для перенаправления обоих выходных потоков - stdout и stderr - из команды в файл. Это ярлык Bash для быстрого перенаправления обоих потоков в один и тот же пункт назначения.

Вот как выглядит таблица дескрипторов файлов после того, как Bash перенаправил оба потока:

Как вы можете видеть, и stdout, и stderr теперь указывают на file . Итак, все, что написано в stdout и stderr, записывается в file .

Существует несколько способов перенаправления обоих потоков в один и тот же пункт назначения. Вы можете перенаправлять каждый поток один за другим:

$ command> file 2> & 1

Это гораздо более распространенный способ перенаправления обоих потоков в файл. Сначала stdout перенаправляется в файл, а затем stderr дублируется так же, как stdout. Таким образом, оба потока в конечном итоге указывают на file .

Когда Bash видит несколько перенаправлений, он обрабатывает их слева направо. Давайте рассмотрим шаги и посмотрим, как это происходит. Перед запуском любых команд таблица дескрипторов файлов Bash выглядит так:

Теперь Bash обрабатывает первый файл перенаправления>. Мы видели это раньше, и это делает stdout точкой для файла:

Следующий Bash видит второе перенаправление 2> & 1. Мы не видели этого перенаправления раньше. Этот дубликат файлового дескриптора 2 является копией файлового дескриптора 1, и мы получаем:

Оба потока были перенаправлены в файл.

Однако будьте осторожны! Пишу

команда> файл 2> & 1

это не то же самое, что писать:

$ command 2> & 1> file

Порядок переадресаций имеет значение в Bash! Эта команда перенаправляет только стандартный вывод в файл. Stderr все равно будет печататься на терминале. Чтобы понять, почему это происходит, давайте снова рассмотрим шаги. Поэтому перед запуском команды таблица дескриптора файла выглядит следующим образом:

Теперь Bash обрабатывает перенаправления слева направо. Сначала он видит 2> & 1, поэтому он дублирует stderr на stdout. Таблица дескрипторов файлов:

Теперь Bash видит второй >file перенаправления, >file и перенаправляет stdout в файл:

Вы видите, что здесь происходит? Stdout теперь указывает на файл, но stderr все еще указывает на терминал! Все, что записывается в stderr, все равно печатается на экране! Так что будьте очень, очень осторожны с порядком перенаправления!

Также обратите внимание, что в Bash, написание

$ command &> file

точно такая же, как:

$ command> & file


2>&1 представляет собой конструкцию оболочки POSIX. Вот разбивка, токен с помощью токена:

2 : дескриптор выходного файла « Стандартная ошибка ».

>& : Дублировать оператор дескриптора выходного файла (вариант оператора перенаправления вывода > ). Учитывая [x]>&[y] , дескриптор файла, обозначенный x , делается копией дескриптора выходного файла y .

1 дескриптор выходного файла « Стандартный вывод ».

Выражение 2>&1 копирует дескриптор файла 1 в местоположение 2 , поэтому любой вывод, записанный в 2 («стандартная ошибка») в среде выполнения, переходит в тот же файл, который был первоначально описан 1 («стандартный вывод»).

Дальнейшее объяснение:

Дескриптор файла : «Уникальное неотрицательное целое число для каждого процесса, используемое для идентификации открытого файла с целью доступа к файлу».

Стандартный вывод / ошибка : см. Следующее примечание в разделе « Redirection » документации оболочки:

Открытые файлы представлены десятичными числами, начиная с нуля. Наибольшее возможное значение определяется реализацией; однако все реализации должны поддерживать как минимум от 0 до 9 включительно для использования в приложении. Эти числа называются «файловыми дескрипторами». Значения 0, 1 и 2 имеют особое значение и обычное использование и подразумеваются некоторыми операциями перенаправления; они называются стандартным входом, стандартным выходом и стандартной ошибкой, соответственно. Обычно программы берут свой вход со стандартного ввода и записывают вывод на стандартный вывод. Сообщения об ошибках обычно записываются по стандартной ошибке. Операторам перенаправления может предшествовать одна или несколько цифр (без промежуточных символов) для обозначения номера дескриптора файла.





redirect