Redirecionar o script stderr & stdout para um arquivo, mas manter o stdout para tty também?

3

No meu script, tenho atualmente:

exec > >(tee -a /tmp/history.log) 2>&1

Isso grava o stderr e o stdout de todos os comandos no arquivo de log e no tty. Infelizmente, isso torna o tty muito barulhento, então eu prefiro ter apenas stdout no terminal e stdout e stderr no arquivo (na ordem correta, então abrir o arquivo duas vezes para acrescentar não funcionará). Para a vida de mim, não consigo descobrir a invocação mágica do exec (mesmo usando tee /dev/tty ) necessária para que isso funcione.

    
por David 16.07.2016 / 18:00

4 respostas

3

tee não pode enviar diretamente para um descritor de arquivo, mas você pode usar a substituição de processo com cat para resolvê-lo:

exec 3>&1 &>log 1> >(tee >(cat >&3))

Então, stdout vai para a saída através de fd3, e ambos stdout e stderr vão para o log.

    
por 16.07.2016 / 19:27
2

exec 2>>/tmp/history.log 1> >(tee -a /tmp/history.log >&1) pode funcionar para você, mas não há garantia de que o pedido estará correto. Essa ordenação parece ser um problema bem conhecido, de acordo com aqui e aqui .

Esse comando redireciona o stderr para o arquivo de histórico com 2>>/tmp/history.log , depois o stdout para o mesmo arquivo usando 1> >(tee -a /tmp/history.log . Finalmente, ele direciona de volta para stdout: >&1 .

Há uma ressalva com esse método. Em alguns testes que fiz, existe a possibilidade de um erro na ordenação da saída.

Por exemplo, usei find /etc/ -name interfaces como teste. A saída desse comando sozinha é:

$ find /etc/ -name interfaces
/etc/network/interfaces
find: '/etc/lvm/backup': Permission denied
find: '/etc/lvm/archive': Permission denied
find: '/etc/cups/ssl': Permission denied
/etc/cups/interfaces
find: '/etc/ssl/private': Permission denied
find: '/etc/polkit-1/localauthority': Permission denied

Quando executo find /etc/ -name interfaces 2>>output 1> >(tee -a output >&1) em um script, o arquivo de saída contém isto:

+ find /etc/ -name interfaces
++ tee -a output
find: '/etc/lvm/backup'/etc/network/interfaces
: Permission denied
find: '/etc/lvm/archive': Permission denied
find: '/etc/cups/ssl': Permission denied
find: '/etc/ssl/private': Permission denied
/etc/cups/interfaces
find: '/etc/polkit-1/localauthority': Permission denied

Observe que esta parte do stderr foi dividida em duas linhas:

find: '/etc/lvm/backup': Permission denied

Isso não acontece em todos os casos, mas é algo em que você deve estar ciente. Além disso, como mencionado acima, a ordenação é inconsistente.

    
por 16.07.2016 / 19:20
1
exec 2>> /tmp/history.log | tee -a /tmp/history.log

Isso redireciona o erro padrão antes de chutar a saída padrão para tee , o que significa que seus erros não estão sendo kickados no canal de saída padrão (e, portanto, no terminal).

    
por 16.07.2016 / 19:14
1

Você deseja duplicar a stdout e mesclar uma das cópias com stderr. Portanto, somente stdout deve passar por tee e você terá dois processos diferentes gravando no arquivo de log. A maneira mais simples é abrir o arquivo de log duas vezes:

exec > >(tee -a /tmp/history.log) 2>>/tmp/history.log

Como alternativa, você pode fazer o tee write no mesmo descritor de arquivo usado para a saída direta. Para fazer isso, primeiro redirecione o stderr para o arquivo de log e, em seguida, chame tee para duplicar o stdout para stderr.

exec 2>>/tmp/history.log
exec > >(tee -a /dev/fd/2)

Isso pode resultar em dados fora de ordem , porque o programa pode continuar gravando dados em stderr (indo diretamente para o arquivo de log) enquanto o tee estiver ocupado copiando alguma saída stdout anterior para o arquivo de log .

Para evitar esse reordenamento, os dois fluxos precisam passar pelo mesmo programa que recebe dois canais de entrada. Não há uma ferramenta de linha de comando padrão que receba duas entradas e as processe em ordem. Mesmo com o mesmo programa, ainda há potencial para reordenar devido ao buffer no próprio canal. Não consigo pensar em uma solução para isso.

Além disso, é provável que o programa ative o buffer de saída baseado em tamanho no nível da biblioteca (stdio buffering) porque sua saída não está mais indo para um terminal. Isso resulta em muito mais reordenação. Para evitar isso (com uma possível penalidade de desempenho), você pode desativar o buffering com stdbuf ou unbuffer .

    
por 17.07.2016 / 01:12