перенаправьте КОПИЮ stdout к файлу журнала из самого сценария удара

Я знаю, как перенаправить stdout в файл:

exec > foo.log
echo test

это поместит 'тест' в файл foo.log.

Теперь я хочу перенаправить вывод в файл журнала И сохранить его на stdout

т.е. это может быть сделано тривиально снаружи сценария:

script | tee foo.log

но я хочу сделать, объявляют это в рамках самого сценария

Я попробовал

exec | tee foo.log

но это не работало.

223
задан codeforester 9 August 2019 в 13:56
поделиться

4 ответа

#!/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 ). Обратите внимание, что это приведет к записи цветовых кодов в файл журнала, что сделает его менее читаемым .

283
ответ дан 23 November 2019 в 03:59
поделиться

Внутри файла сценария поместите все команды в круглые скобки, например:

(
echo start
ls -l
echo end
) | tee foo.log
18
ответ дан 23 November 2019 в 03:59
поделиться

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

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 потом в родительской оболочке).

-1
ответ дан 23 November 2019 в 03:59
поделиться

Bash 4 имеет команду coproc , которая устанавливает именованный канал для команды и позволяет общаться через него.

1
ответ дан 23 November 2019 в 03:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: