it-swarm.com.ru

Что в «Шелл» означает «2> & 1»?

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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

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

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

2006
Tristan Havelick

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

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

2226
Ayman Hourieh
echo test > afile.txt

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

echo test 1> afile.txt

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

echo test 2> afile.txt

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

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

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

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

echo test 2>&1

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

556
dbr

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

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

Приложение: 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

Примечание: если 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 ;-)

294
F. Hauri

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

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

$ 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

82
Deen John

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

77
Colin Burnett

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

Это допускает некоторые довольно сложные хитрости.

54
paxdiablo

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


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

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

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

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


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

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

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

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

17
wjordan

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.

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

17
Marcus Thornton

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

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

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

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

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

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

16
Andrioid

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

dup2(1, 2);

Смотрите справочная страница .

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

command >file 2>&1

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

command 2>&1 >file

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

11
ams

При условии, что /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

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

6
Matijs

Люди, всегда помните подсказку paxdiablo о текущем местоположении цели перенаправления ... Это есть важно.

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

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

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

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

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

6
Kurt Pfeifle

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

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

$cmd 2>filename
cat filename

command not found

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

2>&1

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

5
Kalanidhi

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

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

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

[n]<Word

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

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

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

[n]>Word

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

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

[n]<&digit-

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

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

[n]>&digit-

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

Ref:

man bash

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

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

PS:

В большинстве случаев man был мощным инструментом для изучения Linux.

4
yurenchen

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

один совет: somecmd >1.txt 2>&1 правильный, а somecmd 2>&1 >1.txt полностью неправильный без эффекта!

1
fzyzcjy