Как перенаправить вывод в файл и стандартный вывод

990

В bash вызов fooбудет отображать любой вывод этой команды на стандартный вывод.

Вызов foo > outputперенаправит любой вывод этой команды в указанный файл (в данном случае «output»).

Есть ли способ перенаправить вывод в файл и показать его на стандартный вывод?

SCdF
источник
3
Если кто-то только что оказался здесь в поисках записи ошибок в файл, взгляните на - unix.stackexchange.com/questions/132511/…
Murphy
2
Замечание по терминологии: при выполнении foo > outputданных будет выводится на стандартный вывод и стандартный вывод является файл с именем output. То есть запись в файл - это запись в стандартный вывод. Вы спрашиваете, возможно ли написать как на стандартный вывод, так и на терминал.
Уильям Перселл
2
@WilliamPursell Я не уверен, что ваши разъяснения улучшают ситуацию :-) Как насчет этого: OP спрашивает, возможно ли направить стандартный вывод вызываемой программы как в файл, так и в стандартный вывод вызывающей программы (последний - это стандартный вывод, который вызываемая программа будет делать наследовать, если ничего особенного не было сделано, то есть терминал, если вызывающая программа представляет собой интерактивный сеанс bash). И, возможно, они также хотят направить stderr вызываемой программы аналогичным образом («любой вывод этой команды» может быть разумно истолкован как означающий включение stderr).
Дон Хэтч

Ответы:

1383

Команда, которую вы хотите, называется tee:

foo | tee output.file

Например, если вы заботитесь только о stdout:

ls -a | tee output.file

Если вы хотите включить stderr, выполните:

program [arguments...] 2>&1 | tee outfile

2>&1перенаправляет канал 2 (стандартный вывод / стандартная ошибка) в канал 1 (стандартный вывод / стандартный вывод), так что оба записываются как стандартный вывод. Он также направляется в данный выходной файл как teeкоманда.

Кроме того, если вы хотите добавить в файл журнала, используйте tee -aкак:

program [arguments...] 2>&1 | tee -a outfile
Zoredache
источник
173
Если OP хочет, чтобы «весь вывод» был перенаправлен, вам также нужно захватить stderr: «ls -lR / 2> & 1 | tee output.file»
Джеймс Брэди,
45
@evanmcdonnal Ответ не является неправильным, он может быть недостаточно конкретным или полным в зависимости от ваших требований. Конечно, существуют условия, при которых вы можете не захотеть, чтобы stderr был частью сохранения результата в файл. Когда я ответил на это 5 лет назад, я предположил, что ОП хотел только stdout, так как он упомянул stdout в теме поста.
Zoredache
3
Ах, прости, я мог быть немного смущен. Когда я попробовал это, у меня просто не было выхода, возможно, это все шло к stderr.
evanmcdonnal
38
Используйте -aаргумент teeдля добавления содержимого output.fileвместо того, чтобы перезаписывать его:ls -lR / | tee -a output.file
kazy
17
Если вы используете $?впоследствии, он вернет код состояния tee, что, вероятно, не то, что вы хотите. Вместо этого вы можете использовать ${PIPESTATUS[0]}.
LaGoutte
501
$ program [arguments...] 2>&1 | tee outfile

2>&1выводит потоки stderr и stdout tee outfileберет полученный поток и записывает его на экран и в файл «outfile».

Это, вероятно, то, что ищет большинство людей. Скорее всего, какая-то программа или скрипт долго работают и выдают много результата. Пользователь хочет периодически проверять его на предмет прогресса, но также хочет, чтобы вывод был записан в файл.

Проблема (особенно при смешивании потоков stdout и stderr) состоит в том, что существует зависимость от потоков, сбрасываемых программой. Если, например, все записи на стандартный вывод будут не покраснел, но все записи в STDERR являются покраснел, то они будут в конечном итоге из хронологической последовательности в выходном файле и на экране.

Также плохо, если программа выдает только 1 или 2 строки каждые несколько минут, чтобы сообщить о прогрессе. В таком случае, если вывод не был сброшен программой, пользователь даже часами не будет видеть вывод на экране, потому что ни один из них не будет проталкиваться через канал в течение нескольких часов.

Обновление: программа unbuffer, входящая в expectпакет, решит проблему буферизации. Это заставит stdout и stderr немедленно записать на экран и в файл и синхронизировать их при объединении и перенаправлении на tee. Например:

$ unbuffer program [arguments...] 2>&1 | tee outfile
Мэтью Альперт
источник
7
Кто-нибудь знает о «небуфере» для OSX?
Джон Ми
7
Если вы не можете использовать unbuffer, GNU coreutils включает в себя инструмент под названием stdbuff, который можно использовать для предотвращения буферизации вывода следующим образом$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter
1
Если вы используете OS X, в большинстве случаев проще использовать unbuffer, хотя и не в том случае, если вы хотите передать сигналы выполняемой вами команде. Мой комментарий был больше нацелен на пользователей Linux, где coreutils, скорее всего, установлен по умолчанию. @Ethan, посмотрите этот ответ, если вы не уверены в синтаксисе stdbuf: stackoverflow.com/a/25548995/942781
Питер
3
Обратите внимание, что pythonимеет встроенную опцию, -uкоторая снимает буфер с вывода.
fabian789
1
Абсолютный спасатель для обучения моделям ML, где я хочу войти без дополнительного кода, но также посмотреть результаты за часы / дни, необходимые для запуска, спасибо!
рококо,
126

Другой способ, который работает для меня, это

<command> |& tee  <outputFile>

как показано в руководстве по GNU Bash

Пример:

ls |& tee files.txt

Если используется '| &', стандартная ошибка command1 , в дополнение к стандартному выводу , подключается к стандартному вводу command2 через канал; это сокращение для 2> & 1 |. Это неявное перенаправление стандартной ошибки на стандартный вывод выполняется после любых перенаправлений, указанных в команде.

Для получения дополнительной информации см. Перенаправление

tsenapathy
источник
10
Если вы используете $?впоследствии, он вернет код состояния tee, что, вероятно, не то, что вы хотите. Вместо этого вы можете использовать ${PIPESTATUS[0]}.
LaGoutte
1
Этот метод отбрасывает цветной вывод на консоль, есть идеи?
shakram02
Попробуйте: unbuffer ls -l --color = auto | tee files.txt
Лучано Андресс Мартини
17

В первую очередь вы можете использовать решение Zoredache , но если вы не хотите перезаписывать выходной файл, вы должны написать команду с параметром -a следующим образом:

ls -lR / | tee -a output.file
O.Badr
источник
11

Что-то добавить ...

Unbuffer пакета имеет проблемы с поддержкой некоторых пакетов в выпусках fedora и redhat unix.

Откладывая в сторону неприятности

Следующее сработало для меня

bash myscript.sh 2>&1 | tee output.log

Спасибо, ScDF и Мэтью, ваши материалы сэкономили мне много времени ..

nitinr708
источник
7

Использование tail -f outputдолжно работать.

Чак Филлипс
источник
3

Бонусный ответ, так как этот вариант использования привел меня сюда:

В случае, если вам нужно сделать это как какой-то другой пользователь

echo "some output" | sudo -u some_user tee /some/path/some_file

Обратите внимание, что эхо произойдет, когда вы и запись в файл произойдут как «some_user», что НЕ будет работать, если вы запустите эхо как «some_user» и перенаправите вывод с помощью >> «some_file», потому что произойдет перенаправление файла как и ты.

Подсказка: tee также поддерживает добавление с флагом -a, если вам нужно заменить строку в файле другим пользователем, вы можете выполнить sed в качестве нужного пользователя.

jorfus
источник
2

< command > |& tee filename # это создаст файл «имя файла» с статусом команды в качестве контента. Если файл уже существует, он удалит существующий контент и запишет статус команды.

< command > | tee >> filename # это добавит статус к файлу, но не выведет статус команды на standard_output (screen).

Я хочу напечатать что-нибудь с помощью «эхо» на экране и добавить эти данные в файл

echo "hi there, Have to print this on screen and append to a file" 
Киран Сай
источник
1

Вы можете сделать это для всего скрипта, используя что-то подобное в начале скрипта:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

Это редирект как потоки вывода выводит в файл с именем , mylogfile и пусть все идет на стандартный вывод одновременно .

Используются некоторые глупые трюки:

  • использовать execбез команды для настройки перенаправлений,
  • использовать teeдля дублирования выходов,
  • перезапустите скрипт с нужными перенаправлениями,
  • используйте специальный первый параметр (простой NULсимвол, указанный в $'string'специальной нотации bash), чтобы указать, что сценарий перезапускается (никакие эквивалентные параметры не могут использоваться в вашей исходной работе),
  • попытайтесь сохранить исходное состояние выхода при перезапуске сценария с помощью pipefailпараметра.

Некрасиво, но полезно для меня в определенных ситуациях.

Бруно КОФЕ
источник
-13

тройник идеально подходит для этого, но это также сделает работу

ls -lr / > output | cat output
кал
источник
10
Это ошибка, если вывод еще не существует и он не делает то, что вы хотите, если он делает, в целом это бессмысленно. Возможно, вы имели в виду ";" вместо "|" ?
Роберт Гэмбл
6
Даже если вы используете a ;, вывод будет сильно задерживаться во время медленной команды.
Брэд Кох