Como redirecionar e anexar stdout e stderr a um arquivo com o Bash?

1534

Para redirecionar stdout para um arquivo truncado no Bash, eu sei usar:

cmd > file.txt

Para redirecionar stdout no Bash, anexando a um arquivo, eu sei usar:

cmd >> file.txt

Para redirecionar stdout e stderr para um arquivo truncado, eu sei usar:

cmd &> file.txt

Como redireciono stdout e stderr anexando a um arquivo? cmd &>> file.txtnão funcionou para mim.

flybywire
fonte
37
Gostaria de observar que o & outfile é um código específico do Bash (e outros) e não é portátil. O caminho a percorrer portátil (similar às respostas anexando) sempre foi e ainda é> outfile 2> & 1
TheBonsai

Respostas:

1999
cmd >>file.txt 2>&1

O Bash executa os redirecionamentos da esquerda para a direita da seguinte maneira:

  1. >>file.txt: Abra file.txtno modo de acréscimo e redirecione para stdoutlá.
  2. 2>&1: Redirecione stderrpara "stdout para onde está indo atualmente" . Nesse caso, esse é um arquivo aberto no modo de acréscimo. Em outras palavras, &1reutiliza o descritor de arquivo que stdoutatualmente usa.
Alex Martelli
fonte
33
funciona bem! mas existe uma maneira de entender isso ou devo tratar isso como uma construção de basquete atômica?
Flybywire 18/05/09
181
É um redirecionamento simples, as instruções de redirecionamento são avaliadas, como sempre, da esquerda para a direita. >> arquivo: vermelho. STDOUT para arquivo (modo de acréscimo) (abreviação de 1 >> arquivo) 2> & 1: Vermelho. STDERR para "para onde vai o stdout" Observe que a interpretação "redireciona STDERR para STDOUT" está incorreta.
TheBonsai
31
Ele diz "anexa a saída (stdout, descritor de arquivo 1) no arquivo.txt e envia stderr (descritor de arquivo 2) para o mesmo local que o fd1".
Pausado até novo aviso.
2
@TheBonsai no entanto, e se eu precisar redirecionar o STDERR para outro arquivo, mas anexando? Isso é possível?
Arod #
41
se você fizer cmd >>file1 2>>file2isso, deve conseguir o que deseja.
Woodrow Douglass
367

Existem duas maneiras de fazer isso, dependendo da sua versão do Bash.

A maneira clássica e portátil ( Bash pré-4 ) é:

cmd >> outfile 2>&1

Uma maneira não portável, começando com o Bash 4, é

cmd &>> outfile

(analógico para &> outfile)

Para um bom estilo de codificação, você deve

  • decida se a portabilidade é uma preocupação (use o modo clássico)
  • decida se a portabilidade mesmo para o Bash pré-4 é uma preocupação (use o modo clássico)
  • independentemente da sintaxe usada, não a altere no mesmo script (confusão!)

Se o seu script já começar #!/bin/sh(não importa se isso é pretendido ou não), a solução Bash 4 e, em geral, qualquer código específico do Bash, não é o caminho a seguir.

Lembre-se também de que o Bash 4 &>>é apenas uma sintaxe mais curta - ele não apresenta nenhuma nova funcionalidade ou algo parecido.

A sintaxe é (ao lado de outra sintaxe de redirecionamento) descrita aqui: http://bash-hackers.org/wiki/doku.php/syntax/redirection#appending_redirected_output_and_error_output

TheBonsai
fonte
8
Eu prefiro & >>, pois é consistente com &> e >>. Também é mais fácil ler 'anexar saída e erros a este arquivo' do que 'enviar erros à saída, anexar saída a este arquivo'. Nota ao Linux geralmente tem uma versão atual do bash, OS X, no momento da escrita, ainda requer festa de 4 a instalada manualmente via homebrew etc.
mikemaccana
Eu gosto mais porque é mais curto e apenas dois lugares por linha, então o que, por exemplo, o zsh faria com "& >>"?
Phillipp
Também é importante observar que, em um trabalho cron, você tem que usar a sintaxe pré-4, mesmo se o sistema tem Bash 4.
hyperknot
5
O @zsero cron não usa o bash de todo ... ele usa sh. Você pode alterar o shell padrão anexando SHELL=/bin/bashao crontab -earquivo.
Ray Foss
89

No Bash, você também pode especificar explicitamente seus redirecionamentos para arquivos diferentes:

cmd >log.out 2>log_error.out

Anexar seria:

cmd >>log.out 2>>log_error.out
Aaron R.
fonte
6
Redirecionar dois fluxos para o mesmo arquivo usando sua primeira opção fará com que o primeiro escreva "em cima" do segundo, substituindo parte ou todo o conteúdo. Use cmd >> log.out 2> log.out .
Orestis P.
3
Obrigado por capturar isso; você está certo, um vai derrotar o outro. No entanto, seu comando também não funciona. Eu acho que a única maneira de gravar no mesmo arquivo é como foi dado antes cmd >log.out 2>&1. Estou editando minha resposta para remover o primeiro exemplo.
Aaron R.
65

No Bash 4 (assim como no ZSH 4.3.11):

cmd &>>outfile

apenas fora da caixa

AB
fonte
2
@ all: esta é uma boa resposta, pois funciona com o bash e é breve, então editei para garantir que ele mencione explicitamente o bash.
Mikemaccana 20/05
10
@mikemaccana: A resposta do TheBonsai mostra a solução do bash 4 desde 2009
jfs 27/03
52

Isso deve funcionar bem:

your_command 2>&1 | tee -a file.txt

Ele armazenará todos os logs no arquivo.txt e os despejará no terminal.

Pradeep Goswami
fonte
Esta é a resposta correta se você quiser ver a saída no terminal também. No entanto, essa não foi a pergunta originalmente feita.
Mikko Rantalainen 15/04
25

Tente isto

You_command 1>output.log  2>&1

Seu uso do &> x.file funciona no bash4. Desculpe por isso : (

Aqui estão algumas dicas adicionais.

0, 1, 2 ... 9 são descritores de arquivo no bash.

0 significa stdin, 1 significa stdout, 2 significa stderror. 3 ~ 9 é de reposição para qualquer outro uso temporário.

Qualquer descritor de arquivo pode ser redirecionado para outro descritor ou arquivo usando o operador >ou >>(anexar).

Uso: < file_descriptor > > < filename | & file_descriptor >

Consulte http://www.tldp.org/LDP/abs/html/io-redirection.html

Quintus.Zhou
fonte
Seu exemplo fará algo diferente do que o OP pediu: Ele redirecionará o stderr de You_commandpara stdout e o stdout de You_commandpara o arquivo output.log. Além disso, ele não será anexado ao arquivo, mas o substituirá.
Pabouk 31/05
Correto: o descritor de arquivo pode ter qualquer valor maior que 3 para todos os outros arquivos.
Itachi
5
Sua resposta mostra o erro de redirecionamento de saída mais comum: redirecionando STDERR para onde o STDOUT está apontando no momento e somente depois redirecionando o STDOUT para o arquivo. Isso não fará com que o STDERR seja redirecionado para o mesmo arquivo. A ordem dos redirecionamentos é importante.
Jan Wikholm
1
isso significa que eu deveria primeiro redirecionar STDERROR para STDOUT e depois redirecionar STDOUT para um arquivo. 1 > output.log 2>&1
Quintus.Zhou
1
@ Quintus.Zhou Yup. Seus redirecionamentos de versão são errados e, ao mesmo tempo, arquivados.
Alex Yaroshevich
11

Estou surpreso que, em quase dez anos, ninguém postou essa abordagem ainda:

Se estiver usando versões mais antigas do bash, onde &>>não estiver disponível, você também poderá:

(cmd 2>&1) >> file.txt

Isso gera um subshell, portanto é menos eficiente do que a abordagem tradicional cmd >> file.txt 2>&1e, consequentemente, não funcionará para comandos que precisam modificar o shell atual (por exemplo cd, pushd), mas essa abordagem parece mais natural e compreensível para mim:

  1. Redirecione stderr para stdout.
  2. Redirecione o novo stdout anexando a um arquivo.

Além disso, os parênteses removem qualquer ambiguidade de ordem, especialmente se você deseja canalizar stdout e stderr para outro comando.

jamesdlin
fonte
Essa implementação causa um processo extra para a execução do sistema. O uso da sintaxe cmd >> file 2>&1funciona em todos os shells e não precisa de um processo extra para ser executado.
Mikko Rantalainen 15/04
@MikkoRantalainen Eu já expliquei que gera um subshell e é menos eficiente. O objetivo dessa abordagem é que, se a eficiência não é grande coisa (e raramente é), é mais fácil lembrar e difícil errar.
jamesdlin 15/04