Я знаю, как перенаправить stdout в файл:
exec > foo.log
echo test
это поместит 'тест' в файл foo.log.
Теперь я хочу перенаправить вывод в файл журнала И сохранить его на stdout
т.е. это может быть сделано тривиально снаружи сценария:
script | tee foo.log
но я хочу сделать, объявляют это в рамках самого сценария
Я попробовал
exec | tee foo.log
но это не работало.
#!/usr/bin/env bash
# Redirect stdout ( > ) into a named pipe ( >() ) running "tee"
exec > >(tee -i logfile.txt)
# Without this, only stdout would be captured - i.e. your
# log file would not contain any error messages.
# SEE (and upvote) the answer by Adam Spiers, which keeps STDERR
# as a separate stream - I did not want to steal from him by simply
# adding his answer to mine.
exec 2>&1
echo "foo"
echo "bar" >&2
Обратите внимание, что это bash
, а не sh
. Если вы вызываете сценарий с sh myscript.sh
, вы получите сообщение об ошибке в строке синтаксической ошибки рядом с неожиданным токеном '>'
.
Если вы работаете с ловушками сигналов, вы можете использовать параметр tee -i
, чтобы избежать прерывания вывода при возникновении сигнала. (Спасибо JamesThomasMoon1979 за комментарий.)
Инструменты, которые изменяют свой вывод в зависимости от того, пишут ли они в канал или терминал (например, ls
с использованием цветов и вывода в столбцы), обнаружат указанную выше конструкцию. это означает, что они выводятся в трубу.
Есть опции для принудительного раскрашивания / колонизации (например, ls -C --color = always
). Обратите внимание, что это приведет к записи цветовых кодов в файл журнала, что сделает его менее читаемым .
Внутри файла сценария поместите все команды в круглые скобки, например:
(
echo start
ls -l
echo end
) | tee foo.log
Ни одно из этих решений не является идеальным, но вот пара вещей, которые вы можете попробовать:
exec >foo.log
tail -f foo.log &
# rest of your script
или
PIPE=tmp.fifo
mkfifo $PIPE
exec >$PIPE
tee foo.log <$PIPE &
# rest of your script
rm $PIPE
Второй вариант оставит файл канала если что-то пойдет не так с вашим скриптом, что может быть или не быть проблемой (то есть, возможно, вы могли бы rm
потом в родительской оболочке).
Bash 4 имеет команду coproc
, которая устанавливает именованный канал для команды и позволяет общаться через него.