Как перенаправить вывод в файл и стандартный вывод - PullRequest
812 голосов
/ 07 января 2009

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

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

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

Ответы [ 10 ]

1109 голосов
/ 07 января 2009

Требуемая команда называется tee:

foo | tee output.file

Например, если вам нужен только стандартный вывод:

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
469 голосов
/ 28 августа 2011
$ program [arguments...] 2>&1 | tee outfile

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

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

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

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

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

$ unbuffer program [arguments...] 2>&1 | tee outfile
111 голосов
/ 20 марта 2015

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

<command> |& tee  <outputFile>

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

Пример:

ls |& tee files.txt

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

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

16 голосов
/ 15 августа 2014

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

ls -lR / | tee -a output.file
11 голосов
/ 26 июня 2015

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

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

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

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

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

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

6 голосов
/ 07 января 2009

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

3 голосов
/ 22 октября 2015

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

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

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

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

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

1 голос
/ 01 февраля 2018

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

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

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

echo "hi there, Have to print this on screen and append to a file" 
0 голосов
/ 03 мая 2019

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

#!/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

Это перенаправляет выходные данные как stderr, так и stdout в файл с именами mylogfile и , и все сразу отправляется на стандартный вывод .

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

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

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

0 голосов
/ 07 января 2009

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

ls -lr / > output | cat output
...