Что означает "2>&1"?
Я пытаюсь объединить потоки stderr
и stdout
в один поток stdout
и применяю для этого следующий синтаксис к команде:
2>&1
Например, следующая команда позволяет мне увидеть несколько первых ошибок при компиляции файла main.cpp
:
g++ main.cpp 2>&1 | head
Но что именно означает конструкция 2>&1
?
5 ответ(ов)
Файловый дескриптор 1 — это стандартный вывод (stdout
).
Файловый дескриптор 2 — это стандартная ошибка (stderr
).
Сначала конструкция 2>1
может показаться хорошим способом перенаправить stderr
в stdout
. Однако на самом деле она будет интерпретироваться как "перенаправить stderr
в файл с именем 1
".
Символ &
указывает, что то, что идет до и после, является файловым дескриптором, а не именем файла. Поэтому мы используем 2>&1
. Рассматривайте >&
как оператор слияния перенаправлений.
Чтобы перенаправить стандартный вывод (stdout) в файл file.txt
, вы можете использовать следующую команду:
echo test > file.txt
Эта команда аналогична:
echo test 1> file.txt
Для перенаправления стандартного ошибок (stderr) в файл file.txt
используйте:
echo test 2> file.txt
Синтаксис >&
используется для перенаправления потока в другой дескриптор файла:
- 0 — это stdin (стандартный ввод)
- 1 — это stdout (стандартный вывод)
- 2 — это stderr (стандартный вывод ошибок)
Для перенаправления stdout в stderr можно использовать следующую команду:
echo test 1>&2 # аналогично, можно записать как echo test >&2
Чтобы перенаправить stderr в stdout, выполните:
echo test 2>&1
Таким образом, в конструкции 2>&1
:
2>
перенаправляет stderr в (неуказанный) файл.&1
перенаправляет stderr в stdout.
Номера обозначают файловые дескрипторы (fd).
- Ноль — это
stdin
(стандартный ввод) - Один — это
stdout
(стандартный вывод) - Два — это
stderr
(стандартный вывод ошибок)
2>&1
переадресовывает дескриптор 2 (stderr) в дескриптор 1 (stdout).
Это работает для любого количества файловых дескрипторов, если программа их использует.
Если вы вдруг забудете, можете взглянуть на файл /usr/include/unistd.h
:
/* Стандартные файловые дескрипторы. */
#define STDIN_FILENO 0 /* Стандартный ввод. */
#define STDOUT_FILENO 1 /* Стандартный вывод. */
#define STDERR_FILENO 2 /* Стандартный вывод ошибок. */
На эту тему стоит отметить, что я писал инструменты на C, которые используют нестандартные файловые дескрипторы для пользовательского логирования, так что вы их не увидите, если не переадресуете вывод в файл или что-то подобное.
Конструкция 2>&1
перенаправляет стандартный поток ошибок (stderr
) в текущее местоположение стандартного вывода (stdout
). Этот нюанс, касающийся порядка операций, часто игнорируется в других ответах.
Вы можете перенаправить любой поток вывода на другой с помощью данного метода, но чаще всего он используется для объединения потоков stdout
и stderr
в один поток для последующей обработки.
Вот несколько примеров:
# Ищем строку ERROR в stdout и stderr.
foo 2>&1 | grep ERROR
# Запускаем просмотрщик less без вмешательства stderr в вывод.
foo 2>&1 | less
# Отправляем stdout и stderr в файл (с добавлением) и терминал.
foo 2>&1 | tee /dev/tty >> outfile
# Направляем stderr в обычное место, а stdout в файл.
foo > outfile1 2>&1 > outfile2
Обратите внимание, что последний пример не перенаправит stderr
в outfile2
— он перенаправит его в то место, где находился stdout
на момент, когда был встретен аргумент (outfile1
), а затем перенаправит stdout
в outfile2
.
Это позволяет производить довольно изощренные манипуляции с потоками вывода.
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.
Я рекомендую вам попытаться разобраться в этих механизмах.
Как установить переменную на вывод команды в Bash?
Разница между sh и Bash
Как сделать паузу в shell-скрипте на одну секунду перед продолжением?
Bash инструмент для получения n-й строки из файла
Назначение значений по умолчанию для переменных оболочки одной командой в bash