Что в оболочке означает «2>&1»?
Вопрос
В оболочке 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
совершенно неверно без эффекта!