Вопрос: Что означает «2> & 1» в оболочке?


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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

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

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


1716


источник


Ответы:


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

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


1918



echo test > afile.txt

..redirects stdout to afile.txt, Это то же самое, что и делать.

echo test 1> afile.txt

Чтобы перенаправить stderr, вы ...

echo test 2> afile.txt

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

Вы можете перенаправить stdout на stderr, выполнив ..

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

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

echo test 2>&1

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


471



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

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

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

Символ >имею в виду перенаправление ,

  • >имею в виду отправить в целом завершенный файл , перезапись цели, если она существует (см. noclobberбаш в # 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! С новой версией ( >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

для этого особый case, есть синтаксис ярлыка: &>... или >&

$ 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

в консоль ;-)


255



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


67



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

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


49



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

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

$ command &> file

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

Вот как выглядит таблица дескриптора файла после того, как bash перенаправил оба потока: enter image description here

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

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

$ command> file 2> & 1

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

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

enter image description here

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

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 видит второй файл перенаправления и перенаправляет stdout в файл:

enter image description here

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

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

$ command &> file

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

$ command> & file


43



2>&1 is a POSIX shell construct. Here is a breakdown, token by token:


2: "Standard error" output file descriptor.

>&: Duplicate an Output File Descriptor operator (a variant of Output Redirection operator >). Given [x]>&[y], the file descriptor denoted by x is made to be a copy of the output file descriptor y.

1 "Standard output" output file descriptor.

The expression 2>&1 copies file descriptor 1 to location 2, so any output written to 2 ("standard error") in the execution environment goes to the same file originally described by 1 ("standard output").


Further explanation:

File Descriptor: "A per-process unique, non-negative integer used to identify an open file for the purpose of file access."

Standard output/error: Refer to the following note in the Redirection section of the shell documentation:

Open files are represented by decimal numbers starting with zero. The largest possible value is implementation-defined; however, all implementations shall support at least 0 to 9, inclusive, for use by the application. These numbers are called "file descriptors". The values 0, 1, and 2 have special meaning and conventional uses and are implied by certain redirection operations; they are referred to as standard input, standard output, and standard error, respectively. Programs usually take their input from standard input, and write output on standard output. Error messages are usually written on standard error. The redirection operators can be preceded by one or more digits (with no intervening characters allowed) to designate the file descriptor number.


13



To answer your question: It takes any error output (normally sent to stderr) and writes it to standard output (stdout).

This is helpful with, for example 'more' when you need paging for all output. Some programs like printing usage information into stderr.

To help you remember

  • 1 = standard output (where programs print normal output)
  • 2 = standard error (where programs print errors)

"2>&1" simply points everything sent to stderr, to stdout instead.

I also recommend reading this post on error redirecting where this subject is covered in full detail.


12



2 is the Console standard error.

1 is the Console standard output.

This is the standard Unix, Windows also follows the POSIX. E.g. when you run

perl test.pl 2>&1

The standard error is redirected to standard output, so you can see both outputs together.

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

After execution, you can see all the output, including errors, in the debug.log.

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

Then standard output goes to out.log, and standard error to err.log.

I suggest you to try to understand these.


12



From a programmer's point of view, it means precisely this:

dup2(1, 2);

See the man page.

Understanding that 2>&1 is a copy also explains why ...

command >file 2>&1

... is not the same as ...

command 2>&1 >file

The first will send both streams to file, whereas the second will send errors to stdout, and ordinary output into file.


9