Estou convertendo um script de bash para zsh e estou me debatendo há dias com a saída. Eu quero que o stdout e o stderr vão para o console e para um arquivo de log. Eu tentei de tudo que posso encontrar online, mas sem alegria. Eu li a seção de redirecionamento do manual do zsh, mas não encontrei nada que ajudasse, embora deva admitir que não está claro para mim.
Aqui estão as coisas que tentei perto do início do script, experimentalmente, e seus resultados:
exec 2>&1 | tee -i test.log # everything in console, log created but empty
exec 2>&1 | tee -i > test.log # everything in console, log created but empty
exec 1>>$LOG; exec 2>&1 # everything in log, none in console
exec 2>&1; exec 1>>$LOG # console gets errors only; log stdout only
exec &> >(tee "$LOG") # works in bash, error in zsh
exec > >(tee -i ${LOG?}) 2>&1 # error
exec |& tee $LOG # error
exec > >(tee $LOG) 2>&1 # error
Eu também tentei entender os multios da opção zsh, mas não consegui entender muito. Deveria estar ativado por padrão, mas não o encontro na lista de opções quando executo setopt
. Nem quando corro setopt multios
. Quando corro unsetopt multios
, vejo a opção nomultios
, mas isso não parece ajudar
Entendo que perguntas semelhantes foram feitas e respondidas, mas as respostas estão principalmente na lista acima e não funcionaram para mim.
Não acho que seja relevante, mas também configurei um log de depuração que obtém o descritor de arquivo 3. É apenas para linhas de saída de depuração que terminam com >&3.
Observação para quem procura essa solução: os testes executivos acima foram feitos com um shebang confuso e os resultados com isso corrigido foram um pouco diferentes. Além da solução de Gairfowl, abaixo, também funcionou:
exec > >(tee $LOG) 2>&1
Isso parece funcionar:
Teste:
Altere
>>log.txt
para>log.txt
se quiser sobrescrever o arquivo todas as vezes, em vez de anexá-lo. Isso também funcionou>>$log
quando alog
variável foi definida como um nome de arquivo. Amultios
sintaxe é descrita nesta resposta e há um pouco mais de informação aqui .Isso requer que
multios
esteja ativado - como você observou, esse é o padrão.set -o
(nb: set, not setopt) pode ser usado para exibir o status de todas as opções;setopt
sem parâmetros lista apenas as opções que foram alteradas do padrão.Algumas notas sobre as peças:
exec ...
- oexec
builtin substituirá o shell atual por um novo processo. Quando é chamado assim sem um argumento de comando, a substituição é outra instância dezsh
, com os redirecionamentos definidos para os novos valores na linha de comando. O efeito é quase idêntico a invocar um comando com esses redirecionamentos na linha de comando, por exemplo{print abc;print -u2 def} >&1 >log.txt 2>&1
, .>&1
- redirecionarstdout
parastdout
. Sim, é um pouco redundante - este é um sinal paramultios
o que queremos continuar a enviarstdout
para o seu destino atual (que provavelmente é o terminal), além dos seguintes redirecionamentos.>>log.txt
- adicione um redirecionamento parastdout
o arquivolog.txt
no modo de acréscimo. Este é ummultios
comportamento específico; agora a saída padrão está sendo enviada para dois lugares, por meio de um mecanismozsh
que se parece muito comtee
.2>&1
- enviarstderr
para o mesmo lugar questdout
. Graças aos dois redirecionamentos anteriores,stdout
está indo para dois lugares, então isso também enviastderr
a saída para o arquivo e (provavelmente) para o terminal.print -u<n>
- apenas para teste. A-u
opção envia a saída para o descritor de arquivo<n>
.