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 no modo de acréscimo)?
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 no modo de acréscimo)?
Respostas:
O problema é que, quando você redireciona sua saída, ela não está mais disponível para o próximo redirecionamento. Você pode canalizar tee
em um subshell para manter a saída para o segundo redirecionamento:
( cmd | tee -a file2 ) >> file1 2>&1
ou se você gostaria de ver a saída no terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
Para evitar a inclusão do stderr do primeiro tee
para file1
, você deve redirecionar o stderr do seu comando para alguns descritor de arquivo (por exemplo, 3), e depois adicioná-lo ao stdout novamente:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(obrigado @ fra-san)
Com zsh
:
cmd >& out+err.log > out.log
No modo de acréscimo:
cmd >>& out+err.log >> out.log
Em zsh
e desde que a mult_ios
opção não tenha sido desativada, quando um descritor de arquivo (aqui 1) é redirecionado várias vezes para gravação, o shell implementa um built-in tee
para duplicar a saída para todos os destinos.
cmd >& file1 > file2
Você pode: marcar stdout (usando um sed UNBUFFERED, ou seja: sed -u ...
:), o stderr também vai para stdout (sem marcação, pois não passou por essa marcação com sed) e, assim, conseguir diferenciar os 2 no arquivo de log resultante.
O seguinte: é lento (pode ser seriamente otimizado, usando por exemplo um script perl em vez de um tempo ...; faça ...; feito, por exemplo, que gerará sub-conchas e comandos em todas as linhas!), Estranho (parece que eu preciso dos 2 {} estágios em um renomear stdout e depois no outro adicionar o "falled through" stderr), etc. Mas é: uma " prova de conceito ", que tentará manter a saída solicita o máximo de stdout e stderr o máximo possível:
#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
{
{ for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
} | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
case "$line" in
${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;;
*) printf "%s\n" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
ls unknown
) para imprimir algo no stderr? >&2 echo "error"
seria ótimo. (2) tee
pode acrescentar vários arquivos ao mesmo tempo. (3) Por que não apenas em cat
vez de grep "^"
? (4) seu script falhará quando a saída stderr começar _stdout_
. (5) por que?
ls loop
produzirá tanto stdout quanto stderr, misturados (alternativamente), em uma ordem controlada; para que possamos verificar se mantivemos essa ordem stderr / stdout, apesar da marcação de stdout 2): gnu tail, talvez, mas não cauda regular (por exemplo, em Aix.). 3): grep "^" também mostra os dois nomes de arquivos. 4): isso pode ser alterado pela variável 5): o exemplo complicado funciona em discos antigos (ex, antigo Aix) onde eu testei (nenhum perl disponível).
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
...)
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
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
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 um conteúdo do descritor de arquivo. Portanto, uma idéia inicial de ter uma saída em dois arquivos seria usar:
... | tee file1 file2
Isso reproduz o stdin do tee nos dois arquivos (1 e 2), deixando a saída do tee ainda não utilizada. Mas precisamos acrescentar (usar -a
) e precisamos apenas de uma cópia. Isso resolve os dois problemas:
... | tee -a file1 >>file2
Para fornecer tee
com stdout (aquele a repetir), precisamos consumir stderr diretamente fora do comando. De uma maneira, se a ordem não for importante (a ordem de saída (provavelmente) será preservada conforme gerada, o que ocorrer primeiro será armazenado primeiro). Ou:
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 algumas conchas. A opção 3 usa um subshell adicional (mais lento), mas usa os nomes de arquivo apenas uma vez.
Porém, se o stdout precisar ser o primeiro (qualquer que seja a saída da ordem gerada), precisamos armazenar o stderr para anexá-lo ao arquivo no final (primeira solução publicada).
sponge
:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
No interesse da diversidade:
Se o seu sistema suportar /dev/stderr
, então
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
vai funcionar. A saída padrão do cmd
é enviada para o stdout e o stderr do pipeline. O erro padrão do cmd
desvio tee
e sai do stderr do pipeline.
tão
cmd
ecmd
, misturado.É 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 ), as
file1
linhas podem ficar fora de ordem.
out+err
eout
dizer aqui. Nomes de arquivos? Fluxos a serem redirecionados?