Что означает «2> & 1» в оболочке? - PullRequest
2010 голосов
/ 04 мая 2009

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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

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

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

Ответы [ 15 ]

2230 голосов
/ 04 мая 2009

Файловый дескриптор 1 - это стандартный вывод (stdout).
Файловый дескриптор 2 является стандартной ошибкой (stderr).

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

556 голосов
/ 04 мая 2009
echo test > afile.txt

перенаправляет стандартный вывод на afile.txt. Это то же самое, что и

echo test 1> afile.txt

Чтобы перенаправить stderr, вы должны:

echo test 2> afile.txt

>& - это синтаксис для перенаправления потока в другой дескриптор файла - 0 - это стандартный ввод, 1 - стандартный вывод, а 2 - стандартный вывод.

Вы можете перенаправить стандартный вывод в stderr, выполнив:

echo test 1>&2 # or echo test >&2

Или наоборот:

echo test 2>&1

Итак, вкратце ... 2> перенаправляет stderr в файл (не указан), добавление &1 перенаправляет stderr в stdout.

294 голосов
/ 29 апреля 2013

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

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

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

Примечание: &9 дескриптор возникнет самопроизвольно из-за ) 9>&2.

Приложение: nota! С новой версией (>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

Примечание: если существует 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

в консоли ; -)

83 голосов
/ 29 октября 2016

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

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

$ command &> file

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

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

Enter image description here

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

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

$ command> file 2> & 1

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

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

Enter image description here

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

Enter image description here

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

Enter image description here

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

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

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

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

$ command 2> & 1> file

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

Enter image description here

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

Enter image description here

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

Enter image description here

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

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

$ command &> file

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

$ command> & file

77 голосов
/ 04 мая 2009

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

  • Ноль stdin
  • Один из них stdout
  • Два - это 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, которые используют нестандартные файловые дескрипторы для пользовательской регистрации, поэтому вы не увидите его, если не перенаправите его в файл или что-то еще.

54 голосов
/ 04 мая 2009

Эта конструкция отправляет стандартный поток ошибок (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.

Это допускает довольно изощренную хитрость.

17 голосов
/ 25 декабря 2016

2>&1 - это конструкция оболочки POSIX. Вот разбивка, токен по токену:


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

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

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

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


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

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

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

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

17 голосов
/ 19 июля 2013

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.

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

16 голосов
/ 04 мая 2009

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

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

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

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

"2> & 1" просто указывает все, что отправлено на stderr, вместо этого на stdout.

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

11 голосов
/ 03 декабря 2015

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

dup2(1, 2);

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

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

command >file 2>&1

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

command 2>&1 >file

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...