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 STDINetc. 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 sintaxe 2>&1simplesmente aponta o descritor 2 para onde quer que seja 1. > file.txtsimplesmente abre file.txtpara 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, duplicenciar 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 as system()chamadas desse script terminarão nesse arquivo temporário. Quando terminar, você pode redirecionar dupseu 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:
Em que ordem o shell executa comandos e redireciona o fluxo?
Esquerda para a direita.
<command> > file.txt 2>&1
fork fora de um novo processo.
- Abra
file.txte armazene seu ponteiro no descritor de arquivo 1 (STDOUT).
- Aponte STDERR (descritor de arquivo 2) para o que o fd 1 apontar agora (que novamente já está aberto, é
file.txtclaro).
exec a <command>
Aparentemente, isso redireciona o stderr para o stdout primeiro e, em seguida, o stdout resultante é redirecionado para o arquivo.txt.
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.