Eu estava tentando redirecionar ambos stdout
e stderr
para um arquivo hoje, e me deparei com isso:
<command> > file.txt 2>&1
Aparentemente, isso redireciona stderr
para stdout
primeiro e, em seguida, o resultado stdout
é redirecionado para file.txt
.
No entanto, por que não é o pedido <command> 2>&1 > file.txt
? Alguém poderia naturalmente ler isso como (assumindo a execução da esquerda para a direita) o comando sendo executado primeiro, o stderr
redirecionado para stdout
e, em seguida, o resultante stdout
sendo gravado file.txt
. Mas o acima só redireciona stderr
para a tela.
Como o shell interpreta os dois comandos?
command-line
bash
redirect
Trem Heartnet
fonte
fonte
bash
manual . A propósito, redirecionamentos não são comandos.execv
syscall -family é chamado para realmente entregar o subprocesso para o comando que está sendo iniciado, o shell fica fora do loop (não há mais código em execução nesse processo) ) e não tem como controlar o que acontece a partir desse momento; redirecionamentos, portanto, todos devem ser realizados antes da execução começa, enquanto o shell tem uma cópia de si mesmo em execução no processo quefork()
ed para executar o seu comando no.Respostas:
Quando você executa o
<command> 2>&1 > file.txt
stderr, ele é redirecionado2>&1
para onde o stdout está atualmente, seu terminal. Depois disso, stdout é redirecionado para o arquivo>
, mas stderr não é redirecionado com ele, portanto permanece como saída do terminal.Com o
<command> > file.txt 2>&1
stdout, ele é redirecionado primeiro para o arquivo e>
, em seguida,2>&1
redireciona o stderr para onde o stdout está indo, que é o arquivo.Pode parecer contra-intuitivo começar, mas quando você pensa nos redirecionamentos dessa maneira e lembre-se de que eles são processados da esquerda para a direita, faz muito mais sentido.
fonte
Pode fazer sentido se você o rastrear.
No começo, stderr e stdout vão para a mesma coisa (geralmente o terminal, que eu chamo aqui
pts
):Estou me referindo a stdin, stdout e stderr pelos números de descritores de arquivos aqui: eles são descritores de arquivos 0, 1 e 2, respectivamente.
Agora, no primeiro conjunto de redirecionamentos, temos
> file.txt
e2>&1
.Tão:
> file.txt
:fd/1
agora vai parafile.txt
. With>
,1
é o descritor de arquivo implícito quando nada é especificado, portanto, é1>file.txt
:2>&1
:fd/2
agora vai para ondefd/1
que vá atualmente :Por outro lado, com
2>&1 > file.txt
a ordem sendo revertida:2>&1
:fd/2
agora vai para onde querfd/1
que vá, o que significa que nada muda:> file.txt
:fd/1
agora vai parafile.txt
:O ponto importante é que o redirecionamento não significa que o descritor de arquivo redirecionado seguirá todas as alterações futuras no descritor de arquivo de destino; só vai assumir a corrente estado .
fonte
2.
segunda parte;fd/1 -> file.txt
e nãofd/2 -> file.txt
.Eu acho que ajuda pensar que o shell configurará o redirecionamento à esquerda primeiro e concluirá antes de configurar o próximo redirecionamento.
A linha de comando do Linux, de William Shotts, diz
isso faz sentido, mas então
mas, na verdade, podemos redirecionar stdout para stderr após redirecionar stderr para um arquivo com o mesmo efeito
Portanto, em
command > file 2>&1
, o shell envia stdout para um arquivo e, em seguida, envia stderr para stdout (que está sendo enviado para um arquivo). Enquanto nocommand 2>&1 > file
shell primeiro redireciona o stderr para o stdout (ou seja, exibe-o no terminal onde o stdout normalmente vai) e depois, redireciona o stdout para o arquivo. O TLCL é enganoso ao dizer que devemos redirecionar o stdout primeiro: já que podemos redirecionar o stderr para um arquivo primeiro e depois enviar o stdout para ele. O que não podemos fazer é redirecionar o stdout para o stderr ou vice-versa antes do redirecionamento para um arquivo. Outro exemploPodemos pensar que isso descartaria o stdout para o mesmo local que o stderr, mas não redireciona o stdout para o stderr (a tela) primeiro e depois redireciona o stderr, como quando tentamos o contrário ...
Espero que isso traga um pouco de luz ...
fonte
Você já tem algumas respostas muito boas. Quero enfatizar, porém, que existem dois conceitos diferentes envolvidos aqui, cuja compreensão ajuda tremendamente:
Segundo plano: descritor de arquivo x tabela de arquivos
Seu descritor de arquivo é apenas um número 0 ... n, que é o índice na tabela de descritores de arquivos em seu processo. Por convenção, STDIN = 0, STDOUT = 1, STDERR = 2 (observe que os termos
STDIN
etc. aqui são apenas símbolos / macros usados pela convenção em algumas linguagens de programação e páginas de manual, não há um "objeto" real chamado STDIN; o objetivo desta discussão, STDIN é 0, etc.).Essa tabela de descritor de arquivo em si não contém nenhuma informação sobre qual é o arquivo real. Em vez disso, ele contém um ponteiro para uma tabela de arquivos diferente; o último contém informações sobre um arquivo físico real (ou dispositivo de bloco, canal ou qualquer outra coisa que o Linux possa endereçar através do mecanismo de arquivo) e mais informações (isto é, para leitura ou gravação).
Portanto, quando você usa
>
ou<
no seu shell, basta substituir o ponteiro do respectivo descritor de arquivo para apontar para outra coisa. A sintaxe2>&1
simplesmente aponta o descritor 2 para onde quer que seja 1.> file.txt
simplesmente abrefile.txt
para escrever e permite que STDOUT (decsriptor de arquivo 1) aponte para isso.Existem outras vantagens, por exemplo
2>(xxx)
( por exemplo : criar um novo processo em execuçãoxxx
, criar um canal, conectar o descritor de arquivo 0 do novo processo à extremidade de leitura do canal e conectar o descritor de arquivo 2 do processo original à extremidade de gravação do tubo).Essa também é a base para a "manipulação de arquivos mágicos" em outro software que não o seu shell. Por exemplo, você pode, em seu script Perl,
dup
licenciar o descritor de arquivo STDOUT para outro (temporário) e depois reabrir o STDOUT para um arquivo temporário recém-criado. A partir deste ponto, toda a saída STDOUT do seu próprio script Perl e todas assystem()
chamadas desse script terminarão nesse arquivo temporário. Quando terminar, você pode redirecionardup
seu STDOUT para o descritor temporário em que o salvou e pronto, tudo é como antes. Você pode até escrever nesse descritor temporário enquanto isso, enquanto sua saída STDOUT real for para o arquivo temporário, você ainda poderá realmente enviar coisas para o STDOUT real (geralmente, o usuário).Responda
Para aplicar as informações básicas fornecidas acima à sua pergunta:
Esquerda para a direita.
fork
fora de um novo processo.file.txt
e armazene seu ponteiro no descritor de arquivo 1 (STDOUT).file.txt
claro).exec
a<command>
Isso faria sentido se houvesse apenas uma tabela, mas, como explicado acima, há duas. Os descritores de arquivo não estão apontando recursivamente um para o outro; não faz sentido pensar em "redirecionar STDERR para STDOUT". O pensamento correto é "apontar STDERR para onde quer que STDOUT aponte". Se você alterar STDOUT mais tarde, o STDERR permanecerá onde está, não será magicamente acompanhado de outras alterações no STDOUT.
fonte
O pedido é da esquerda para a direita. O manual do Bash já cobriu o que você pediu. Citação da
REDIRECTION
seção do manual:e algumas linhas depois:
É importante observar que o redirecionamento é resolvido primeiro antes da execução de qualquer comando! Consulte https://askubuntu.com/a/728386/295286
fonte
É sempre da esquerda para a direita ... exceto quando
Assim como na matemática, fazemos da esquerda para a direita, exceto a multiplicação e a divisão antes da adição e subtração, exceto as operações entre parênteses (+ -) antes da multiplicação e divisão.
De acordo com o guia para iniciantes do Bash aqui ( Guia para iniciantes do Bash ), existem 8 ordens de hierarquia do que vem primeiro (antes da esquerda para a direita):
Portanto, é sempre da esquerda para a direita ... exceto quando ...
fonte