Вопрос

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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

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

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

Это было полезно?

Решение

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

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

Другие советы

echo test > afile.txt

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

echo test 1> afile.txt

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

echo test 2> afile.txt

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

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

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

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

echo test 2>&1

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

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

Некоторые особенности синтаксиса могут иметь важное значение.Есть несколько небольших примеров перенаправлений, 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

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

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

Приложение:нота! Один и тот же новый синтаксис в обоих случаях:

$ 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

4б- Теперь я дам вам подумать:

$ 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

в консоль ;-)

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

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

  

$ command & amp; > file

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

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

 Введите описание изображения здесь

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

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

  

$ command > file 2 > & amp; 1

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

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

 Введите описание изображения здесь

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

 Введите описание изображения здесь

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

 Введите описание изображения здесь

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

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

  

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

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

  

$ command 2 > & 1 > file

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

 Введите описание изображения здесь

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

 Введите описание изображения здесь

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

 Введите описание изображения здесь

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

Также нет

Числа относятся к файловым дескрипторам (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, которые используют нестандартные файловые дескрипторы для пользовательского ведения журналов, поэтому вы не увидите их, пока не перенаправите их в файл или что-то еще.

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

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

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

<Ч>

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

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

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

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

<Ч>

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

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

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

  

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

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.

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

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

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

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

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

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

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

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

dup2(1, 2);

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

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

command >file 2>&1

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

command 2>&1 >file

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

Люди, всегда помните Паксдиаблонамек на текущий местоположение цели перенаправления...Это является важный.

Моя личная мнемоника для 2>&1 оператор это:

  • Думать о & как значение 'and' или 'add' (персонаж — амперы-и, не так ли?)
  • Итак, получается: 'перенаправление 2 (stderr) куда 1 (stdout) уже/в настоящее время есть и добавлять оба потока'.

Та же самая мнемоника работает и для другого часто используемого перенаправления: 1>&2:

  • Думать о & значение and или add...(вы поняли про амперсанд, да?)
  • Итак, получается: 'перенаправление 1 (стандартный вывод) туда, где 2 (stderr) уже/в настоящее время есть и добавлять оба потока'.

И всегда помните:читать цепочки перенаправлений приходится "с конца", справа налево(нет слева направо).

При условии, что / foo не существует в вашей системе, а / tmp - & # 8230;

$ 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

это стенография

Это похоже на передачу ошибки на стандартный вывод или в терминал.

То есть cmd не является командой:

$cmd 2>filename
cat filename

command not found

Ошибка отправляется в файл следующим образом:

2>&1

Стандартная ошибка отправляется на терминал.

  

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

     

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

     

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

[n]<word
     

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

     

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

     

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

[n]>word
     

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

     

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

[n]<&digit-
     

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

     

Аналогично, оператор перенаправления

[n]>&digit-
     

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

Ссылка

man bash

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

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

PS:

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

0 для ввода, 1 для стандартного вывода и 2 для стандартного ввода.

Один совет . somecmd > 1.txt 2 > & amp; 1 является правильным, в то время как somecmd 2 > & amp; 1 > 1.txt совершенно неверно без эффекта!

scroll top