Разница между 2> & 1> output.log и 2> & 1 | тройник output.log

35

Я хотел знать разницу между следующими двумя командами

2>&1 > output.log 

а также

2>&1 | tee output.log

Я видел, как один из моих коллег использовал второй вариант для перенаправления. Я знаю, что делает 2> & 1, мой единственный вопрос: какова цель использования tee, где можно использовать простой оператор перенаправления ">"?

Чандер Шивдасани
источник

Ответы:

11

Глядя на две команды отдельно:

utility 2>&1 >output.log 

Здесь, поскольку перенаправления обрабатываются слева направо, стандартный поток ошибок сначала перенаправляется туда, куда идет стандартный поток вывода (возможно, на консоль), а затем стандартный поток вывода перенаправляется в файл. Стандартный поток ошибок не будет перенаправлен в этот файл.

Видимый эффект этого состоит в том, что вы получаете то, что вырабатывается при стандартной ошибке на экране, и то, что вырабатывается при стандартном выводе в файл.

utility 2>&1 | tee output.log

Здесь вы перенаправляете стандартную ошибку в то же место, что и стандартный поток вывода. Это означает, что оба потока будут переданы в teeутилиту как один смешанный выходной поток, и что эти стандартные выходные данные будут сохранены в данный файл tee. Данные будут дополнительно воспроизводиться teeв консоли (это то tee, что делает, он дублирует потоки данных).

Какой из этих способов использовать, зависит от того, чего вы хотите достичь.

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


Дополнительные замечания:

Видимый эффект первой команды,

utility 2>&1 >output.log 

будет так же, как

utility >output.log

Т.е. стандартный вывод идет в файл, а стандартная ошибка - в консоль.

Если в конце каждой из вышеперечисленных команд будет добавлен дальнейший этап обработки, будет большая разница:

utility 2>&1 >output.log | more_stuff

utility >output.log      | more_stuff

В первом конвейере more_stuffбудет получено то, что изначально является стандартным потоком ошибок, в utilityкачестве стандартных входных данных, тогда как во втором конвейере, поскольку это только результирующий стандартный поток вывода, который когда-либо отправляется через канал, more_stuffчасть конвейера ничего не получит. читать на своем стандартном входе.

Кусалананда
источник
С помощью команды " utility 2>&1 | tee output.log, вы хотите сказать, что поскольку 1 направлен на тройник, то 2 тоже. Поскольку тройник дублирует поток, выходные данные отображаются как на консоли, так и записываются в файл? Следовательно, разница между utility 2>&1 > output.logи utility 2>&1 | tee output.logявляется teeтем , что он дублирует поток это будет правильно.?
Мотивированный
С примерами utility 2>&1 > output.log | more_stuffи utility >ouput.log| more_stuff , is the difference that more_stuff` имеет стандартную ошибку вывода на консоль в качестве входа more_stuff? Поскольку во втором примере нет вывода на консоль, по сути, нет ввода в more_stuff? Если да, это не ясно, так как в предыдущем абзаце вы заметили, что стандартный вывод идет в файл, а стандартная ошибка - в консоль
мотивировано
@ Мотивированный Ваш первый комментарий мне кажется правильным, да. Что касается второго комментария: в первой команде more_stuffбудет получено то, что utilityпервоначально было отправлено в поток ошибок (но которое было перенаправлено на стандартный вывод). Не потому, что он оказался бы на консоли, если бы more_stuffего там не было, а потому, что он идет в стандартный поток вывода . Во второй команде ничего неmore_stuff получает, так как нет стандартного вывода с левой стороны конвейера. Поток ошибок из все равно попадет на консоль во 2-й команде. utility
Кусалананда
Спасибо. Вы имеете в виду это, потому что команда utility > output.log | more_stuffне приводит к выводу в стандартном потоке вывода с точки зрения стандартной ошибки?
мотивировано
@Mooted Так как левая часть не производит ничего при стандартном выводе (он перенаправлен), никакие данные не будут отправляться по каналу.
Кусалананда
24

Редакционная заметка

Пожалуйста, не забудьте прочитать комментарии к этому ответу - Дероберт .


Оригинальный ответ

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

2>&1 | tee output.logто же самое с 2>&1битом, он объединяет стандартный вывод и стандартную ошибку в стандартный поток вывода. Затем он передает это через teeпрограмму, которая отправит свой стандартный ввод в стандартный вывод (например cat), а также в файл. Таким образом, он объединяет два потока (ошибка и вывод), а затем выводит их на терминал и в файл.

Суть в том, что первая отправляет stderr/ stdoutв файл, а вторая отправляет его как в файл, так и в стандартный вывод (который, вероятно, является терминалом, если вы не находитесь внутри другой конструкции, которая перенаправляет стандартный вывод).

Я упоминаю эту последнюю возможность, потому что вы можете иметь такие вещи, как:

(echo hello | tee xyzzy.txt) >plugh.txt

где ничего не заканчивается на терминале.

derobert
источник
13
-1 У вас правильный синтаксис, но не семантика. Выполнить cat /doesnotexist 2>&1 >output.txt- вы увидите см. cat: /doesnotexist: No such file or directoryВывод на терминал и output.txt - пустой файл. Порядок приоритета и закрытия находятся в игре: 2>&1(дублируйте fd2 с текущего fd1), затем >output.txt(перенаправьте fd1 в output.txt, не изменяя ничего больше). Причина, которая 2>&1 |отличается, из-за порядка приоритета: |раньше >.
Arcege
5
Этот ответ в корне неверен по существу во всех отношениях . Многие из приведенных ниже ответов лучше, но я думаю, что этот ответ Кусалананды - самый ясный.
Майкл Гомер
2
@ user14408: Если вы когда-нибудь создадите учетную запись в Unix и Linux и получите этот ответ, пожалуйста, не стесняйтесь удалять мою редакционную заметку, как только вы ответите на комментарии.
Дероберт
8

Первая команда выполнит другую задачу:

После

2>&1 > output.log 

старый STDOUT будет сохранен (скопирован) в STDERR, а затем STDOUT будет перенаправлен в файл.

Итак, стандартный вывод перейдет в файл, а стандартный вывод в консоль.

И в

 2>&1 | tee output.log

оба потока будут перенаправлены на тройник. Tee будет дублировать любой ввод в свой стандартный вывод (консоль в вашем случае) и в файл ( output.log).

И есть еще одна форма первого:

    > output.log  2>&1

это перенаправит STDOUT и STDERR в файл.

osgx
источник
4

Первый выводит только в файл. Второй выводит как в файл, так и на экран.


источник
4

Причина 2>&1 | teeзаключается в том, чтобы иметь возможность записывать как stdout, так и stderr в файл журнала и одновременно видеть его на экране. Это также может быть сделано >output.txt 2>&1 & tail -f, но вы не будете знать, когда прервана фоновая команда - завершена ли программа или она работает без вывода. Это 2>&1 | teeбыла общая идиома для программистов.

Arcege
источник
Вы хотите сказать, что 2> & 1> file.txt, например, не будет захватывать как stdout, так и stderr в file.txt?
мотивировано
0

Давайте сначала посмотрим пример кода:

#include <stdio.h>
main() 
{
// message 1, on stdout (using  printf)
printf("%s",          "message 1, on stdout (using  printf)\n");

// message 2, on stdout (using fprintf)
fprintf(stdout, "%s", "message 2, on stdout (using fprintf)\n");

// message 3, on stderr (using fprintf)
fprintf(stderr, "%s", "message 3, on stderr (using fprintf)\n");
}

Давайте сравним результаты:
./helloerror
+ файл: нет сообщения; консоль: сообщение 1,2,3;

./helloerror >error.txt
+ файл: сообщение 1,2; консоль: сообщение 3;

./helloerror 2>&1 >error.txt
+ файл: сообщение 1,2; консоль: сообщение 3;
+ так же, как ./helloerror> error.txt

./helloerror >error.txt 2>&1
+ файл: сообщение 3,1,2; консоль: нет сообщения;
+ обратите внимание, что сначала идет порядок 3, затем 1, затем 2

./helloerror | tee error.txt 2>&1
+ файл: сообщение 1,2; консоль: сообщение 3,1,2;
+ обратите внимание, что сначала идет порядок 3, затем 1, затем 2

./helloerror 2>&1 | tee error.txt
+ файл: сообщение 3,1,2; консоль: сообщение 3,1,2;

Использовать: -> если нужно,
./helloerror >error.txt 2>&1
чтобы все (stdout + stderr) сообщения находились в файле, но не выводились на консоль

./helloerror 2>&1 | tee error.txt
-> если нужно, чтобы все (stdout + stderr) сообщения находились в файле и выводились на консоль

Хари Перев
источник
-1

Вот статья, в которой обобщены выходные потоки Unix: http://www.devcodenote.com/2015/04/unix-output-streams.html

Фрагмент из поста:

Есть 3 стандартных выходных потока:

STDIN - Standard Input - Writes from an input device to the program
STDOUT - Standard Output - Writes program output to screen unless specified otherwise.
STDERR - Standard Error Output - Writes error messages. Also printed to the screen unless specified otherwise.
Абхишек Джайн
источник