Como posso alcançar
cmd >> file1 2>&1 1>>file2
Ou seja, o stdout e o stderr devem redirecionar para um arquivo (arquivo1) e apenas o stdout (arquivo2) deve redirecionar para outro (ambos em modo append)?
Como posso alcançar
cmd >> file1 2>&1 1>>file2
Ou seja, o stdout e o stderr devem redirecionar para um arquivo (arquivo1) e apenas o stdout (arquivo2) deve redirecionar para outro (ambos em modo append)?
O problema é que quando você redireciona sua saída, ela não está mais disponível para o próximo redirecionamento. Você pode canalizar para
tee
um subshell para manter a saída para o segundo redirecionamento:ou se você quiser ver a saída no terminal:
Para evitar adicionar o stderr do primeiro
tee
afile1
, você deve redirecionar o stderr do seu comando para algum descritor de arquivo (por exemplo, 3), e depois adicionar isso ao stdout novamente:(obrigado @fra-san)
Com
zsh
:No modo de acréscimo:
Em
zsh
, e desde que amult_ios
opção não tenha sido desabilitada, quando um descritor de arquivo (aqui 1) é redirecionado várias vezes para gravação, o shell implementa um built-intee
para duplicar a saída para todos os destinos.Você poderia: marcar stdout (usando um sed UNBUFFERED, ou seja:
sed -u ...
), fazer stderr também ir para stdout (não marcado, pois não passou por esse sed de marcação) e, assim, ser capaz de diferenciar os 2 no arquivo de log resultante.O seguinte: é lento (pode ser seriamente otimizado, usando, por exemplo, um script perl em vez do while ... ; do ... ;done, por exemplo, que gerará subshells e comandos em todas as linhas!), estranho (parece que eu preciso dos 2 {} estágios para em um renomear stdout e depois no outro adicionar o stderr "falled through"), etc. Mas é: uma " prova de conceito ", que tentarei manter a ordem da saída o máximo possível de stdout & stderr:
Se a ordem de saída deve ser: stdout then stderr ; não há solução apenas com redirecionamento.
O stderr deve ser armazenado em um arquivo temporal
Descrição:
A única maneira de redirecionar uma saída (um fd como stdout ou stderr) para dois arquivos é reproduzi-la. O comando
tee
é a ferramenta correta para reproduzir o conteúdo de um descritor de arquivo. Então, uma ideia inicial para ter uma saída em dois arquivos seria usar:Isso reproduz o stdin de tee para ambos os arquivos (1 e 2) deixando a saída de tee ainda não utilizada. Mas precisamos anexar (use
-a
) e precisamos apenas de uma cópia. Isso resolve os dois problemas:Para fornecer
tee
stdout (aquele a repetir), precisamos consumir stderr diretamente do comando. Uma maneira, se a ordem não for importante (a ordem de saída será (provavelmente) preservada conforme gerada, o que for gerado primeiro será armazenado primeiro). Qualquer:cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
A opção 2 funciona apenas em alguns shells. A opção 3 usa um subshell adicional (mais lento), mas usa os nomes dos arquivos apenas uma vez.
Mas se stdout deve ser o primeiro (qualquer saída de ordem gerada), precisamos armazenar stderr para anexá-lo ao arquivo no final (primeira solução postada).
No interesse da diversidade:
Se o seu sistema suportar
/dev/stderr
, entãovai funcionar. A saída padrão do
cmd
é enviada para o stdout e o stderr do pipeline. O erro padrão docmd
ignora otee
e sai o stderr do pipeline.Então
cmd
, ecmd
, misturados.É então uma simples questão de enviar esses fluxos para os arquivos corretos.
Como em quase qualquer abordagem como essa (incluindo a resposta de Stéphane ),
file1
pode deixar as linhas fora de ordem.