Por que o comportamento de 'command 1file.txt 2file.txt' é diferente de 'command 1file.txt 2 & 1'?

18

Quando você quiser redirecionar stdout e stderr para o mesmo arquivo, use command 1>file.txt 2>&1 ou command &>file.txt . Mas por que o comportamento de command 1>file.txt 2>file.txt é diferente dos dois comandos acima?

O seguinte é um comando de verificação.

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

No que se refere aos resultados, parece que a segunda string de eco substitui a primeira cadeia de eco quando você executa command 1>file.txt 2>file.txt , mas não sei por que isso ocorrerá. (Existe uma referência em algum lugar?)

    
por fhiyo 10.09.2017 / 18:01

2 respostas

41

Você precisa saber duas coisas:

  • Um descritor de arquivos aberto conhecido pelo lado do modo de aplicação de um processo faz referência a um objeto de kernel interno conhecido como descrição do arquivo , que é uma instância de um arquivo aberto . Pode haver várias descrições de arquivo por arquivo e vários descritores de arquivo compartilhando uma descrição de arquivo.
  • A posição atual do arquivo é um atributo de uma descrição do arquivo . Portanto, se vários descritores de arquivo forem mapeados para uma única descrição de arquivo, todos eles compartilharão a mesma posição de arquivo atual, e uma alteração na posição do arquivo executada usando um descritor de arquivo afetará todos os outros descritores de arquivo.

    Tais alterações são promulgadas por processos que chamam as chamadas de sistema read() / readv() , write() / writev() , lseek() e semelhantes. O comando echo chama write() / writev() , claro.

Então o que acontece é isto:

  • command 1>file.txt 2>&1 cria apenas uma descrição de arquivo, porque o shell só abre um arquivo uma vez. O shell torna ambos a saída padrão e os descritores de arquivo de erro padrão mapeiam para aquela descrição de arquivo único. Ele duplica a saída padrão para o erro padrão. Assim, uma gravação via descritor de arquivo moverá a posição do arquivo atual compartilhado: cada gravação vai após a gravação anterior da descrição do arquivo comum. E como você pode ver os resultados dos comandos echo não substituem um ao outro.
  • command 1>file.txt 2>file.txt cria duas descrições de arquivo, porque o shell abre o mesmo arquivo duas vezes, em resposta aos dois redirecionamentos explícitos. Os descritores de arquivo de saída padrão e de erro padrão são mapeados para duas descrições de arquivo diferentes, que, por sua vez, são mapeadas para o mesmo arquivo único. As duas descrições de arquivo têm posições de arquivo atuais totalmente independentes, e cada gravação vai imediatamente a gravação anterior na mesma descrição de arquivo. E como você pode ver, o resultado é que o que é escrito via um pode sobrescrever o que está escrito pelo outro, de várias maneiras diferentes, de acordo com a ordem em que você executa as gravações.

Leitura adicional

por 10.09.2017 / 22:06
16

Usar > diz para sobrescrever o arquivo. Como você tem stdout e stderr gravando no arquivo em duas operações diferentes, a última a ser gravada sobrescreve a primeira.

Você pode fazer:

command 1>>file.txt 2>>file.txt

ou

command &>file.txt Apenas bash v4 e acima.

>> diz para anexar o arquivo para não substituir a saída das operações anteriores.

&> é apenas uma maneira mais fácil de escrever 2>&1

    
por 10.09.2017 / 18:04