Como um comando pode ter mais de uma saída?

5

Em esta resposta , na parte inferior, Gilles menciona que um comando pode ter mais de uma saída ou entrada.

Sim, há cat foo bar | something , por ter foo e bar como entradas, e há tee para saídas; mas isso não parece ser o que ele está falando.

Como um programa pode ter mais de uma entrada ou saída?

    
por strugee 19.10.2013 / 07:47

3 respostas

9

O exemplo cat foo bar não é o que eu quis dizer. Aqui cat tem apenas uma entrada e uma saída de cada vez.

tee é um exemplo: ela é enviada para todos os argumentos, além de sua saída padrão ao mesmo tempo. Usando o mesmo tipo de diagrama de arte ASCII como em minha resposta anterior , veja como o tee foo bar se parece quando está operando em um terminal.

   +------------------+    
   |       tee        |    
===|<stdin            |         +------------+
→  |                  |         |  terminal  |
   |           stdout>|=========|<input      |
   |                  |   → ##==|<           |
   |                  |     ||  +------------+
   |           stderr>|=====##
   |                  |   →
   |                  |       +-------------+
   |                3>|=======|> file "foo" |
   |                  |   →   +-------------+
   |                  |       +-------------+
   |                4>|=======|> file "bar" |
   |                  |   →   +-------------+
   |                  |    
   +------------------+    

Neste exemplo, tee está enviando saída “útil” para três canais: para o terminal (porque é onde sua saída padrão está conectada) e para dois arquivos. Além disso, tee tem mais um canal de saída para erros.

Um programa normalmente tem três canais de entrada / saída, identificados pelo seu descritor de arquivo número:

  • entrada padrão (stdin para abreviar, descritor de arquivo numero 0);
  • saída padrão (stdout para abreviar, descritor de arquivo número 1);
  • erro padrão (stderr para breve, descritor de arquivo número 2).

O propósito dos descritores de arquivo 0, 1 e 2 é apenas uma questão de convenção - nada reforça que um programa não pode tentar escrever no descritor de arquivo 0 ou ler dos descritores 1 e 2 - mas esta é uma convenção que é basicamente universalmente seguido.

Se você executar um programa a partir de um terminal, os descritores de arquivo 0, 1 e 2 começarão a ser conectados a esse terminal, a menos que tenham sido redirecionados. Outros descritores de arquivos começam fechados e serão usados se o programa abrir outros arquivos.

Em particular, todos os comandos têm duas saídas: saída padrão (para a carga útil do comando, a saída “útil”) e erro padrão (para mensagens de erro ou informativas).

Um pipeline no shell ( command1 | command2 | command3 | … ) conecta a saída padrão de cada comando à entrada padrão do próximo comando. O erro padrão de todos os comandos vai para o terminal (a menos que seja redirecionado).

Os shells fornecem maneiras de redirecionar outros descritores de arquivos. Você provavelmente encontrou 2>&1 ou 2>file para redirecionar o erro padrão. Vejo Quando você usaria um descritor de arquivo adicional? e os outros posts com links para exemplos de manipulações de outros descritores de arquivos.

Shells ricos em recursos também oferecem substituição de processos para generalizar o redirecionamento de arquivos para comandos canalizados, para que você não seja limitado para um pipe linear com cada comando com uma única entrada e uma única saída.

Poucos comandos tentam acessar os descritores de arquivo acima de 2, exceto depois de abrirem um arquivo (a abertura de um arquivo escolhe um descritor de arquivo livre e retorna seu número para o aplicativo). Um exemplo é o GnuPG, que espera ler os dados para criptografar / decodificar / assinar / verificar em sua entrada padrão e gravar o resultado na saída padrão. Pode ser dito para ler uma senha em um descritor de arquivo diferente com a opção --passphrase-fd . O GnuPG também tem opções para relatar dados de status em outros descritores de arquivos, para que você possa ter a saída da carga útil no stdout, as mensagens de erro no stderr e as informações de status em outro descritor de arquivo. Veja um exemplo em que a saída de um comando canalizado é usada como uma frase secreta:

echo fjbeqsvfu | rot13 | gpg -d --passphrase-fd=3 3<&0 <file.encrypted >file.plaintext
    
por 20.10.2013 / 03:08
3

Sim. Por exemplo, cat foo bar | less fornece duas entradas (arquivo foo e barra de arquivos) e gera as duas para menos. vim foo* produzirá todos os arquivos começando com foo no vim. Depois de revisar cada arquivo, você pode alternar para a próxima saída com: n (ou: wn se você alterou alguma coisa). Eu acho que Gilles explicou isso muito bem. Se você estiver usando pipe (|), ele obtém a saída de um comando, insere-o em outro comando e, em seguida, gera o resultado. Esse é outro exemplo de múltiplas saídas.

    
por 19.10.2013 / 07:56
3

Os comandos podem ter mais de um fluxo de saída e não quero dizer gravando em arquivos ou soquetes. Considere a maioria das ferramentas GNU (por exemplo, grep ) que imprime erros em stderr e a saída esperada em stdout. Enquanto em um shell interativo ambos são mesclados (2 > & 1), você ainda pode tratá-los separadamente. Ele não termina aí, já que você pode usar descritores de arquivo extras se o programa ou bloco de código o suportar.

Exemplo envolvido:

{
  grep NORMAL log.txt
  grep WARN log.txt 1>&3
  grep ERROR log.txt 1>&4
} 1> normals.txt 3> warnings.txt 4> errors.txt # 2>/dev/null
    
por 19.10.2013 / 13:32