Скопируйте stdout и stderr в файл журнала и оставьте их на консоли в самом скрипте


11

Используя bash, как мне скопировать stderr и stdout в файл журнала, а также оставить их отображенными на консоли?

Я хотел бы сделать это в самом скрипте, используя exec.

Я пробовал с

exec &>> log.out

echo "This is stdout"
echo "This is stderr" >&2

Но вышесказанное ничего не печатает на консоли. Как я могу добиться этого в Bash?


На StackOverflow есть ответ с большим количеством голосов, который достаточно подробно отвечает на этот вопрос. stackoverflow.com/a/692407/208257
Дэн Бертон

Ответы:


10

Вы ищете tee.

Смотрите man teeподробности.

Чтобы объединить это exec, вы должны использовать процесс подстановки . (Подробнее man bashсм.)

exec &> >(tee  log.out)
echo "This is stdout"
echo "This is stderr" >&2

Я посмотрел на это. Делаем exec 2>&1 | tee -a log.outтолько распечатки на консоли, ничего в лог-файле. Может быть, я не использую правильный синтаксис?
adarshr

@adarshr Пожалуйста, проверьте ваш код еще раз. Я написал teeв сочетании с процессом замены .
Х.-Дирк Шмитт

1
Это объединяет stdout и stderr и может иметь такой же побочный эффект, как упомянуто в моем ответе.
Стефан Шазелас

@StephaneChazelas Посмотрите на пример кода в вопросе - это было намерение от ОП.
Х.-Дирк Шмитт

Под слиянием я подразумеваю, что теперь ошибки скрипта переходят в стандартный вывод. Так что, если кто-то, the-script | wc -lнапример, сделает это, он также посчитает строки ошибок, и вы не увидите ошибок.
Стефан Шазелас

5

Ты можешь сделать:

: > log # empty log file if necessary
{ { {

  ...the script

} 3>&- | tee -a log >&3 3>&-
exit "${PIPESTATUS[0]}"
} 2>&1 | tee -a log >&2 3>&-
} 3>&1
exit "${PIPESTATUS[0]}"

Вы также можете написать это как:

: > log # empty log file if necessary
exec 2> >(tee -a log >&2) > >(tee -a log)

...the script

Но поскольку bash не ожидает запуска этих процессов >(...), это имеет неприятный эффект: иногда выводить что-то на терминал после возврата команды, что может иметь еще более неприятные последствия (например, молча отбрасывать этот вывод), если атрибут терминала «tostop» включен

В любом случае, создавая stdoutканал в обоих решениях и поскольку две команды независимо выводят выходные данные и сообщения об ошибках, это повлияет на буферизацию вывода и порядок отображения выходных сообщений и сообщений об ошибках.


Я думаю, что ваш второй тройник пропускает редирект на stderr. Это должно быть:tee -a log >&2 3>&-
richvdh

5

Я знаю, что это старый пост, но почему бы просто не сделать это?

echo "hi" >> log.txt #stdout -> log
echo "hi" | tee -a log.txt #stdout -> log & stdout
echo "hi" &>> log.txt #stdout & stderr -> log
echo "hi" |& tee -a log.txt #stdout & stderr -> log & stdout

И, конечно, если вы хотите стандартный вывод, вы можете просто печатать регулярно.

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

Я знаю, что пришел сюда и не получил легкого для понимания / реализации ответа, надеюсь, это поможет кому-то еще, кто борется.

Между прочим, для noobs, как и мой предыдущий self, все, что teeделает команда, это выводит ввод stdin как в stdout, так и в файл (ы), указанные в качестве последующих аргументов. -aозначает добавление, поэтому вы не перезаписываете файл при каждом использовании команды. Если у вас есть дополнительные вопросы, я считаю , это будет очень полезным ресурсом для быстрого обучения Баша.


1
Спасибо за помощь. Я, с другой стороны, совершенно забыл, что я пытался сделать :-)
adarshr

1
+1 за множественные, красивые и простые примеры.
Тим

2

Еще один способ сделать это - использовать перенаправления внутри функций.

#!/bin/bash

function1 () {
    echo 'STDOUT from function 1'
    echo 'STDERR from function 1' >&2
}

function2 () {
    echo 'STDOUT from function 2'
    echo 'STDERR from function 2' >&2
}


function3 () {
    echo 'STDOUT from function 3'
    echo 'STDERR from function 3' >&2
}

main() {
    function1
    function2
    function3
}

main 2>&1 |tee log.txt

Здесь у нас есть mainфункция, которая вызывает все другие функции. Теперь перенаправлять STDOUTи STDERRиз mainфункции tee.


ИМХО, это самый чистый способ сделать это, по крайней мере, для простых случаев. Спасибо.
ACK_stoverflow
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.