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

1554

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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

Мне всегда трудно запомнить это, и мне постоянно нужно искать его, и это связано главным образом с тем, что я не полностью понимаю синтаксис этого конкретного трюка. Может кто-то сломать это и объяснить персонажа по характеру, что означает "2 > и 1"?

  • 40
    @dbr Я не думаю, что это просто bash - я считаю, что это вещь Bourne Shell; следовательно sh, bash, ksh, ash, dash и т. д.
  • 8
    Это часть параграфа перенаправления, описывающего POSIX-совместимые оболочки, или короткую оболочку POSIX. ksh - это оболочка POSIX, например. См .: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Показать ещё 5 комментариев
Теги:
redirect

16 ответов

1763
Лучший ответ

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

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

  • 1
    это имеет какое-то значение для вас, java... 2&1 >> data.log , я видел, как один из моих коллег сделал это?
  • 2
    >> означает добавить вывод в файл data.log.
Показать ещё 14 комментариев
436
echo test > afile.txt

.. перенаправляет stdout на 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

  • 5
    это имеет какое-то значение для вас, java ... 2&1 >> data.log , я видел, как один из моих коллег сделал это?
  • 5
    @Harry, который выглядит как оболочка, которая не является bash, или опечатка .. cmd 2>&1 >> somefile.log добавит stdout / stderr в файл - он в основном такой же, как и выше, с >> file для добавления
Показать ещё 3 комментария
239

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

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

Обратите внимание, что последняя команда в этом параграфе точно такая же, как в предыдущей парагафе, где я писал, похоже, не является ожидаемым поведением (так что это может быть даже ожидаемое поведение).

Ну, есть несколько трюков о перенаправлении, для выполняет разные операции над обеими ouputs:

$ ( 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 to not перезаписать любой существующий файл, синтаксис >| позволяет вам пройти это ограничение:

$ 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 

Nota: если 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

в console; )

107
  • 2 является файловым дескриптором по умолчанию для stderr.
  • 1 является файловым дескриптором по умолчанию для stdout.
  • >& - это синтаксис оболочки для "свернуть предыдущий (первый) файловый дескриптор в будущий (второй) файловый дескриптор".
57

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

47

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

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

  • 5
    Хотя последний пример будет гораздо понятнее: foo> outfile2 2> outfile1
  • 3
    Ясно, да, но это не показывало бы «позиционную» природу перенаправления. Пример является надуманным, так как обычно не полезно делать это в одной строке - метод становится действительно полезным, когда разные стороны несут ответственность за разные части перенаправления. Например, когда скрипт выполняет один бит перенаправления, а вы запускаете его с другим битом.
Показать ещё 2 комментария
26

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

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

$command & > file

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

Вот как выглядит таблица дескриптора файла после того, как bash перенаправил оба потока: Изображение 3843

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

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

$command > файл 2 > & 1

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

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

Изображение 3844

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

Изображение 3845

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

Изображение 3846

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

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

command > file 2 > & 1

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

$command 2 > & 1 > file

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

Изображение 3847

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

Изображение 3848

Теперь bash видит второй файл перенаправления > и перенаправляет stdout в файл:

Изображение 3849

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

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

$command & > file

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

$command > & file

  • 2
    Последние два отличаются, если «команда» оканчивается на число, тогда как это берется как необязательный дескриптор файла для >&
  • 1
    прекрасное объяснение! Спасибо
12

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.

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

  • 0
    Второй пример неверен: так как приоритет порядка STDERR перенаправлен на STDOUT , только STDOUT по умолчанию будет записан в debug.log (не STDERR ), смотрите мой ответ (параграф № 2)! Чтобы оба были перенаправлены в один и тот же файл, вы должны инвертировать директивы перенаправления: perl test.pl > debug.log 2>&1
12

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

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

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

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

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

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

10

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


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

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

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

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


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

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

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

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

8

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

dup2(1, 2);

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

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

command >file 2>&1

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

command 2>&1 >file

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

4

Это точно так же, как paasing ошибка для stdout или терминала. т.е. cmd не команда $ cmd 2 > filename cat filename команда не найдена

Ошибка, отправленная в файл, подобный этому 2 > & 1 ошибка, отправленная на терминал

  • 0
    Этот пример командной строки не понятен. Можете ли вы уточнить?
4

Люди всегда помнят paxdiablo о местоположении текущего адреса перенаправления... Важно .

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

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

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

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

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

2

Если /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

является сокращением

2

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

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

онлайн-версия здесь:
http://www.gnu.org/software/bash/manual/bashref.html#Redirections

пс:

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

0

0 для ввода, 1 для stdout и 2 для stderr.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню