Como redirecionar a saída para um arquivo e stdout


989

No bash, a chamada fooexibia qualquer saída desse comando no stdout.

A chamada foo > outputredirecionaria qualquer saída desse comando para o arquivo especificado (neste caso, 'saída').

Existe uma maneira de redirecionar a saída para um arquivo e exibi-la no stdout?


3
Se alguém só acabou aqui olhando para capturar saída de erro para o arquivo, dê uma olhada - unix.stackexchange.com/questions/132511/...
Murphy

2
Uma observação sobre terminologia: quando você executa foo > outputos dados, ele é gravado em stdout e stdout é o arquivo nomeado output. Ou seja, gravar no arquivo está gravando no stdout. Você está perguntando se é possível escrever no stdout e no terminal.
William Pursell

2
@WilliamPursell Não sei se o seu esclarecimento melhora as coisas :-) Que tal: o OP está perguntando se é possível direcionar o stdout do programa chamado para um arquivo e o stdout do programa de chamada (este último é o stdout que o programa chamado herdar se nada de especial foi feito, ou seja, o terminal, se o programa de chamada for uma sessão de bash interativa). E talvez eles também desejem direcionar o stderr do programa chamado da mesma forma ("qualquer saída desse comando" pode ser razoavelmente interpretada como incluindo stderr).
Don Hatch

Respostas:


1380

O comando que você deseja é nomeado tee:

foo | tee output.file

Por exemplo, se você se importa apenas com stdout:

ls -a | tee output.file

Se você deseja incluir o stderr, faça:

program [arguments...] 2>&1 | tee outfile

2>&1redireciona o canal 2 (erro padrão / stderr) para o canal 1 (saída padrão / padrão), de modo que ambos sejam gravados como padrão. Também é direcionado para o arquivo de saída fornecido, a partir do teecomando

Além disso, se você deseja anexar ao arquivo de log, use tee -acomo:

program [arguments...] 2>&1 | tee -a outfile

173
Se OP quer "todas as saídas" para ser redirecionado, você também vai precisar para stderr grab: "ls -lR / 2> & 1 | T output.file"
James Brady

45
@evanmcdonnal A resposta não está errada, apenas pode não ser específica o suficiente ou completa, dependendo dos seus requisitos. Certamente, existem condições em que você pode não querer o stderr como parte da saída que está sendo salva em um arquivo. Quando eu respondi isso há cinco anos, presumi que o OP só queria stdout, já que ele mencionou stdout no assunto do post.
Zoredache

3
Desculpe, eu poderia estar um pouco confuso. Quando tentei, simplesmente não obtive saída, talvez tudo estivesse indo para o stderr.
evanmcdonnal

38
Use -aargumento teepara o conteúdo acréscimo para output.file, em vez de substituí-lo:ls -lR / | tee -a output.file
Kazy

16
Se você estiver usando $?posteriormente, ele retornará o código de status de tee, que provavelmente não é o que você deseja. Em vez disso, você pode usar ${PIPESTATUS[0]}.
LaGoutte 3/03

501
$ program [arguments...] 2>&1 | tee outfile

2>&1despeja os fluxos stderr e stdout. tee outfilepega o fluxo que obtém e grava na tela e no arquivo "outfile".

Provavelmente é isso que a maioria das pessoas está procurando. A situação provável é que algum programa ou script esteja trabalhando duro por um longo tempo e produzindo muita saída. O usuário deseja verificar periodicamente o progresso, mas também deseja que a saída seja gravada em um arquivo.

O problema (especialmente ao misturar fluxos stdout e stderr) é que existe confiança nos fluxos sendo liberados pelo programa. Se, por exemplo, todas as gravações no stdout não forem liberadas, mas todas as gravações no stderr forem liberadas, elas acabarão fora de ordem cronológica no arquivo de saída e na tela.

Também é ruim se o programa emitir apenas 1 ou 2 linhas a cada poucos minutos para relatar o progresso. Nesse caso, se a saída não fosse liberada pelo programa, o usuário nem veria nenhuma saída na tela por horas, porque nada disso seria empurrado pelo cano por horas.

Atualização: O programa unbuffer, parte do expectpacote, resolverá o problema do buffer. Isso fará com que stdout e stderr gravem na tela e no arquivo imediatamente e os mantenham sincronizados ao serem combinados e redirecionados para tee. Por exemplo:

$ unbuffer program [arguments...] 2>&1 | tee outfile

7
Alguém sabe de um 'buffer' para osx?
31512 John Mee

7
Se você não pode usar unbuffer, coreutils GNU inclui uma ferramenta chamada stdbuff que pode ser usado para impedir que o buffer de saída como assim$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter

1
Se você estiver usando o OS X, é marginalmente mais fácil usar o buffer na maioria dos casos, embora não seja o caso se você deseja transmitir sinais para o comando que está executando. Meu comentário foi mais direcionado a usuários que estão no Linux, onde o coreutils provavelmente está instalado por padrão. @Ethan, consulte esta resposta se você está confuso sobre a sintaxe stdbuf: stackoverflow.com/a/25548995/942781
Peter

3
Observe que pythonpossui uma opção integrada -uque impede a saída de buffer.
precisa saber é o seguinte

1
Salva-vidas absoluto para o treinamento de modelos de ML nos quais desejo registrar sem código extra, mas também ver a saída durante as horas / dias necessários para executar, obrigado!
Rococo

126

Outra maneira que funciona para mim é,

<command> |& tee  <outputFile>

como mostrado no manual do gnu bash

Exemplo:

ls |& tee files.txt

Se '| &' for usado, o erro padrão do command1 , além de sua saída padrão , será conectado à entrada padrão do command2 através do pipe; é uma abreviação de 2> & 1 |. Esse redirecionamento implícito do erro padrão para a saída padrão é executado após qualquer redirecionamento especificado pelo comando.

Para mais informações, consulte redirecionamento


10
Se você estiver usando $?posteriormente, ele retornará o código de status de tee, que provavelmente não é o que você deseja. Em vez disso, você pode usar ${PIPESTATUS[0]}.
precisa saber é

1
Esse método descarta a saída colorida do console, alguma idéia?
shakram02

Tente: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini

17

Você pode usar principalmente a solução Zoredache , mas se não quiser sobrescrever o arquivo de saída, deve escrever tee com a opção -a da seguinte maneira:

ls -lR / | tee -a output.file

11

Algo a acrescentar ...

O unbuffer de pacote possui problemas de suporte em alguns pacotes sob as versões fedora e redhat unix.

Deixando de lado os problemas

Seguindo trabalhou para mim

bash myscript.sh 2>&1 | tee output.log

Obrigado SCDF & matthew suas entradas me salvou muito tempo ..



3

Resposta bônus, pois esse caso de uso me trouxe aqui:

No caso em que você precisa fazer isso como outro usuário

echo "some output" | sudo -u some_user tee /some/path/some_file

Observe que o eco acontecerá enquanto você e a gravação do arquivo ocorrerão como "some_user", o que NÃO funcionará é se você executasse o eco como "some_user" e redirecionasse a saída com >> "some_file" porque o redirecionamento do arquivo ocorrerá como você.

Dica: tee também suporta anexar com o sinalizador -a, se você precisar substituir uma linha em um arquivo como outro usuário, poderá executar sed como o usuário desejado.


2

< command > |& tee filename # isto criará um arquivo "filename" com o status do comando como um conteúdo. Se um arquivo já existir, ele removerá o conteúdo existente e gravará o status do comando.

< command > | tee >> filename # isto acrescentará status ao arquivo, mas não imprimirá o status do comando em standard_output (tela).

Quero imprimir algo usando "eco" na tela e anexar esses dados a um arquivo

echo "hi there, Have to print this on screen and append to a file" 

1

Você pode fazer isso em todo o script usando algo assim no início do script:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

Isso redireciona as saídas stderr e stdout para o arquivo chamado mylogfile e permite que tudo vá para o stdout ao mesmo tempo .

São utilizados alguns truques estúpidos:

  • use execsem comando para configurar redirecionamentos,
  • use teepara duplicar saídas,
  • reinicie o script com os redirecionamentos desejados,
  • use um primeiro parâmetro especial (um NULcaractere simples especificado pela $'string'notação especial do bash) para especificar que o script será reiniciado (nenhum parâmetro equivalente pode ser usado pelo seu trabalho original),
  • tente preservar o status de saída original ao reiniciar o script usando a pipefailopção

Feio, mas útil para mim em certas situações.


-13

tee é perfeito para isso, mas isso também fará o trabalho

ls -lr / > output | cat output

10
Isso é um erro se a saída ainda não existir e ela não fizer o que você deseja, se não existir. Talvez você quis dizer ";" em vez de "|" ?
Robert Gamble

6
Mesmo se você usasse a ;, a saída seria muito atrasada durante um comando lento.
Brad Koch
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.