Diferença entre 2> & 1> output.log e 2> & 1 | tee output.log

35

Eu queria saber a diferença entre os dois comandos a seguir

2>&1 > output.log 

e

2>&1 | tee output.log

Vi um dos meus colegas usar a segunda opção para redirecionar. Eu sei o que 2> & 1 faz, minha única pergunta é qual é o propósito de usar tee onde um simples operador de redirecionamento ">" pode ser usado?

Chander Shivdasani
fonte

Respostas:

11

Observando os dois comandos separadamente:

utility 2>&1 >output.log 

Aqui, como os redirecionamentos são processados ​​da esquerda para a direita, o fluxo de erros padrão será redirecionado primeiro para onde quer que o fluxo de saída padrão vá (possivelmente para o console) e, em seguida, o fluxo de saída padrão será redirecionado para um arquivo. O fluxo de erro padrão não seria redirecionado para esse arquivo.

O efeito visível disso é que você obtém o que é produzido com erro padrão na tela e o que é produzido com a saída padrão no arquivo.

utility 2>&1 | tee output.log

Aqui, você redireciona o erro padrão para o mesmo local que o fluxo de saída padrão. Isso significa que os dois fluxos serão canalizados para o teeutilitário como um único fluxo de saída entrelaçado e que esses dados de saída padrão serão salvos no arquivo especificado por tee. Os dados também seriam reproduzidos teeno console (é isso que teeocorre, ele duplica os fluxos de dados).

Qualquer uma dessas opções depende do que você deseja alcançar.

Observe que você não seria capaz de reproduzir o efeito do segundo pipeline apenas >(como em utility >output.log 2>&1, o que salvaria a saída padrão e o erro no arquivo). Você precisaria usar teepara obter os dados no console e no arquivo de saída.


Notas Adicionais:

O efeito visível do primeiro comando,

utility 2>&1 >output.log 

seria o mesmo que

utility >output.log

Ou seja, a saída padrão vai para o arquivo e o erro padrão vai para o console.

Se uma etapa de processamento adicional fosse adicionada ao final de cada um dos comandos acima, haveria uma grande diferença:

utility 2>&1 >output.log | more_stuff

utility >output.log      | more_stuff

No primeiro pipeline, more_stuffobteria o que originalmente era o fluxo de erro padrão utilitycomo dados de entrada padrão, enquanto no segundo pipeline, uma vez que é apenas o fluxo de saída padrão resultante que é enviado por um canal, a more_stuffparte do pipeline não recebe nada para ler em sua entrada padrão.

Kusalananda
fonte
Com o comando " utility 2>&1 | tee output.log, você quer dizer que, como 1 está sendo direcionado para tee, 2 também. Como tee duplica o fluxo, a saída é exibida no console e gravada no arquivo? Daí a diferença entre utility 2>&1 > output.loge utility 2>&1 | tee output.logé teeque ele duplica o fluxo.Estaria correto?
Motivado
Com os exemplos de utility 2>&1 > output.log | more_stuffe utility >ouput.log| more_stuff , is the difference that more_stuff` tem como saída o erro padrão para o console more_stuff? Como no segundo exemplo, não há saída para o console, essencialmente não há entrada para more_stuff? Se sim, isso não está claro desde o parágrafo anterior, observe que a saída padrão vai para o arquivo e o erro padrão para o console.
Motivado
@Motivated Seu primeiro comentário parece correto para mim, sim. Quanto ao segundo comentário: No primeiro comando, more_stuffreceberia o que utilityoriginalmente foi enviado ao seu fluxo de erros (mas que foi redirecionado para a saída padrão). Não porque acabaria no console se more_stuffnão estivesse lá, mas porque está indo para o fluxo de saída padrão . No segundo comando, nãomore_stuff recebe nada, pois não há saída padrão do lado esquerdo do pipeline. O fluxo de erro de utilityainda terminaria no console no 2º comando.
Kusalananda
Obrigado. Você quer dizer isso porque o comando utility > output.log | more_stuffnão resulta em uma saída no fluxo de saída padrão de um ponto de vista de erro padrão?
Motivado
@Motivated Como o lado esquerdo não produz nada na saída padrão (é redirecionado), nenhum dado será enviado pelo canal.
Kusalananda
24

Nota editorial

Leia os comentários sobre esta resposta - derobert .


Resposta original

2>&1 >output.logsignifica primeiro começar a enviar todos os itens do identificador de arquivo 2 (erro padrão) para o identificador de arquivo 1 (saída padrão) e enviá-lo para o arquivo output.log. Em outras palavras, envie erro padrão e saída padrão para o arquivo de log.

2>&1 | tee output.logé o mesmo com o 2>&1bit, ele combina saída padrão e erro padrão no fluxo de saída padrão. Em seguida, canaliza isso através do teeprograma que enviará sua entrada padrão para sua saída padrão (como cat) e também para o arquivo. Por isso, combina os dois fluxos (erro e saída) e depois envia para o terminal e o arquivo.

A linha inferior é que o primeiro envia stderr/ stdoutpara o arquivo, enquanto o segundo envia para tanto o arquivo e saída padrão (que é provavelmente o terminal a menos que você está dentro de uma outra construção, que reorientou a saída padrão).

Menciono essa última possibilidade, porque você pode ter coisas como:

(echo hello | tee xyzzy.txt) >plugh.txt

onde nada acaba no terminal.

derobert
fonte
13
-1 Você tem a sintaxe correta, mas não a semântica. Executar cat /doesnotexist 2>&1 >output.txt- você verá o cat: /doesnotexist: No such file or directorydisplay exibido no terminal e o output.txt é um arquivo vazio. A ordem de precedência e fechamento estão em jogo: 2>&1(dup fd2 do atual fd1) e, em seguida >output.txt(redirecione o fd1 para o output.txt, sem alterar mais nada). O motivo 2>&1 |é diferente por causa da ordem de precedência: |antes >.
Arcege
5
Esta resposta está fundamentalmente errada em essencialmente todos os aspectos . Muitas das respostas abaixo são melhores, mas acho que essa de Kusalananda é a mais clara.
Michael Homer
2
@ user14408: Se você já fez uma conta no Unix e Linux e reivindicou esta resposta, sinta-se à vontade para remover minha nota editorial depois de abordar os comentários.
derobert 22/01
8

O primeiro comando fará a outra tarefa:

Depois de

2>&1 > output.log 

o antigo STDOUT será salvo (copiado) no STDERR e o STDOUT será redirecionado para o arquivo.

Portanto, o stdout irá para o arquivo e o stderr irá para o console.

E em

 2>&1 | tee output.log

os dois fluxos serão redirecionados para tee. O Tee duplicará qualquer entrada em seu stdout (o console no seu caso) e no arquivo ( output.log).

E há outra forma de primeiro:

    > output.log  2>&1

isso redirecionará STDOUT e STDERR para o arquivo.

osgx
fonte
4

A saída anterior apenas para o arquivo. O segundo gera saída para o arquivo e para a tela.


fonte
4

O motivo 2>&1 | teeé poder capturar stdout e stderr em um arquivo de log e vê-lo na tela ao mesmo tempo. Isso também poderia ser feito >output.txt 2>&1 & tail -f, mas você não saberia quando o comando em segundo plano foi finalizado - o programa foi finalizado ou está sendo executado sem saída. Esse 2>&1 | teeera um idioma comum para programadores.

Arcege
fonte
Você quer dizer que 2> & 1> file.txt, por exemplo, não capturaria stdout e stderr em file.txt?
Motivado
0

Vamos ver um código de exemplo primeiro:

#include <stdio.h>
main() 
{
// message 1, on stdout (using  printf)
printf("%s",          "message 1, on stdout (using  printf)\n");

// message 2, on stdout (using fprintf)
fprintf(stdout, "%s", "message 2, on stdout (using fprintf)\n");

// message 3, on stderr (using fprintf)
fprintf(stderr, "%s", "message 3, on stderr (using fprintf)\n");
}

Vamos comparar os resultados:
./helloerror
+ file: no message; console: mensagem 1,2,3;

./helloerror >error.txt
+ arquivo: mensagem 1,2; console: mensagem 3;

./helloerror 2>&1 >error.txt
+ arquivo: mensagem 1,2; console: mensagem 3;
+ igual a ./helloerror> error.txt

./helloerror >error.txt 2>&1
+ arquivo: mensagem 3,1,2; console: nenhuma mensagem;
+ observe que o pedido 3 é primeiro, depois 1 e 2

./helloerror | tee error.txt 2>&1
+ arquivo: mensagem 1,2; console: mensagem 3,1,2;
+ observe que o pedido 3 é primeiro, depois 1 e 2

./helloerror 2>&1 | tee error.txt
+ arquivo: mensagem 3,1,2; console: mensagem 3,1,2;

Para usar:
./helloerror >error.txt 2>&1
-> se alguém quiser todas as mensagens (stdout + stderr) no arquivo, mas não estiver no console

./helloerror 2>&1 | tee error.txt
-> se alguém quiser todas as mensagens (stdout + stderr) em arquivo e impressas no console

Hari Perev
fonte
-1

Aqui está uma postagem resumindo os fluxos de saída do Unix: http://www.devcodenote.com/2015/04/unix-output-streams.html

Um trecho da postagem:

Existem 3 fluxos de saída padrão:

STDIN - Standard Input - Writes from an input device to the program
STDOUT - Standard Output - Writes program output to screen unless specified otherwise.
STDERR - Standard Error Output - Writes error messages. Also printed to the screen unless specified otherwise.
Abhishek Jain
fonte