A resposta aceita não preserva STDERR como um descritor de arquivo separado. Que significa
./script.sh >/dev/null
não será enviado bar
para o terminal, apenas para o arquivo de log e
./script.sh 2>/dev/null
produzirá ambos foo
e bar
para o terminal. Claramente, esse não é o comportamento que um usuário normal provavelmente espera. Isso pode ser corrigido usando dois processos tee separados, ambos anexando ao mesmo arquivo de log:
#!/bin/bash
# See (and upvote) the comment by JamesThomasMoon1979
# explaining the use of the -i option to tee.
exec > >(tee -ia foo.log)
exec 2> >(tee -ia foo.log >&2)
echo "foo"
echo "bar" >&2
(Observe que o acima não inicialmente trunca o arquivo de log - se você deseja esse comportamento, adicione
>foo.log
para o topo do script.)
A especificação POSIX.1-2008 detee(1)
exige que a saída seja sem buffer, ou seja, nem com buffer de linha; portanto, neste caso, é possível que STDOUT e STDERR possam terminar na mesma linha de foo.log
; no entanto, isso também pode acontecer no terminal, portanto o arquivo de log será um reflexo fiel do que pode ser visto no terminal, se não um espelho exato dele. Se você deseja que as linhas STDOUT sejam separadas de maneira limpa das linhas STDERR, considere o uso de dois arquivos de log, possivelmente com prefixos de carimbo de data em cada linha para permitir a remontagem cronológica posteriormente.