Qual é a diferença entre “Redirection” e “Pipe”?

159

Esta questão pode parecer um pouco estúpida, mas não consigo ver a diferença entre o redirecionamento e os canais.

O redirecionamento é usado para redirecionar a stdout / stdin / stderr, por ex. ls > log.txt .

Pipes são usados para fornecer a saída de um comando como entrada para outro comando, por exemplo, ls | grep file.txt .

Mas por que existem dois operadores para a mesma coisa?

Por que não apenas escrever ls > grep para passar o resultado, isso também não é apenas um tipo de redirecionamento? O que eu sinto falta?

    
por John Threepwood 07.08.2012 / 15:22

7 respostas

183

O pipe é usado para transmitir a saída para outro programa ou utilitário .

O redirecionamento é usado para transmitir a saída para um arquivo ou fluxo .

Exemplo: thing1 > thing2 vs thing1 | thing2

thing1 > thing2

  1. Seu shell executará o programa chamado thing1
  2. Tudo o que as thing1 de saídas serão colocadas em um arquivo chamado thing2 . (Nota - se thing2 existir, será sobrescrito)

Se você quiser passar a saída do programa thing1 para um programa chamado thing2 , poderá fazer o seguinte:

thing1 > temp_file && thing2 < temp_file

qual seria

  1. execute o programa chamado thing1
  2. salve a saída em um arquivo chamado temp_file
  3. execute o programa chamado thing2 , fingindo que a pessoa no teclado digitou o conteúdo de temp_file como entrada.

No entanto, isso é desajeitado, então eles criaram pipes como uma forma mais simples de fazer isso. thing1 | thing2 faz o mesmo que thing1 > temp_file && thing2 < temp_file

EDIT para fornecer mais detalhes para questionar no comentário:

Se > tentasse ser "passar para o programa" e "gravar no arquivo", isso poderia causar problemas em ambas as direções.

Primeiro exemplo: Você está tentando gravar em um arquivo. Já existe um arquivo com esse nome que você deseja sobrescrever. No entanto, o arquivo é executável. Presumivelmente, tentaria executar este arquivo, passando a entrada. Você teria que fazer algo como gravar a saída em um novo nome de arquivo e renomeá-lo.

Segundo exemplo: Como Florian Diesch apontou, e se houver outro comando em outro lugar no sistema com o mesmo nome (que está no caminho de execução). Se você pretendia criar um arquivo com esse nome em sua pasta atual, você estaria preso.

Em terceiro lugar: se você digitar errado um comando, ele não o avisará que o comando não existe. No momento, se você digitar ls | gerp log.txt , ele informará bash: gerp: command not found . Se > significasse ambos, simplesmente criaria um novo arquivo para você (então avise que ele não sabe o que fazer com log.txt ).

    
por David Oneill 07.08.2012 / 15:30
17

Se o significado de foo > bar dependeria do fato de haver um comando chamado bar que tornaria o redirecionamento muito mais difícil e mais propenso a erros: toda vez que eu quiser redirecionar para um arquivo, primeiro tive que verificar se há um comando chamado como meu arquivo de destino.

    
por Florian Diesch 07.08.2012 / 15:40
10

Existe uma diferença vital entre os dois operadores:

  1. ls > log.txt - & gt; Este comando envia a saída para o arquivo log.txt.

  2. ls | grep file.txt - & gt; Este comando envia a saída do comando ls para grep através do uso de pipe ( | ), e o comando grep procura por file.txt na entrada fornecida pelo comando anterior.

Se você tivesse que realizar a mesma tarefa usando o primeiro cenário, então seria:

ls > log.txt; grep 'file.txt' log.txt

Assim, um pipe (com | ) é usado para enviar a saída para outro comando, enquanto o redirecionamento (com > ) é usado para redirecionar a saída para algum arquivo.

    
por Ankit 07.08.2012 / 15:32
8

Do manual de administração do sistema Unix e Linux:

  

Redirecionamento

     

O shell interpreta os símbolos & lt;, & gt ;, e & gt; & gt; como instruções para redirecionar uma entrada ou saída do comando para ou de um arquivo .

     

Tubos

     

Para conectar o STDOUT de um comando ao STDIN de outro use o | símbolo, comumente conhecido como um tubo.

Portanto, minha interpretação é: Se for comando para comando, use um pipe. Se você estiver enviando para ou de um arquivo, use o redirecionamento.

    
por Mr Whatever 16.02.2016 / 01:40
1

Há uma grande diferença sintática entre os dois:

  1. Um redirecionamento é um argumento para um programa
  2. Um canal separa dois comandos

Você pode pensar em redirecionamentos como este: cat [<infile] [>outfile] . Isso implica que a ordem não importa: cat <infile >outfile é o mesmo que cat >outfile <infile . Você pode até mesclar redirecionamentos com outros argumentos: cat >outfile <infile -b e cat <infile -b >outfile estão perfeitamente bem. Além disso, você pode agrupar mais de uma entrada ou saída (as entradas serão lidas seqüencialmente e todas as saídas serão gravadas em cada arquivo de saída): cat >outfile1 >outfile2 <infile1 <infile2 . O destino ou a origem de um redirecionamento pode ser um nome de arquivo ou o nome de um fluxo (como & amp; 1, pelo menos no bash).

Mas os canais separam totalmente um comando de outro comando, você não pode misturá-los com argumentos:

[command1] | [command2]

O pipe pega tudo escrito na saída padrão do comando1 e o envia para a entrada padrão do comando2.

Você também pode combinar tubulação e redirecionamento. Por exemplo:

cat <infile >outfile | cat <infile2 >outfile2

O primeiro cat lerá as linhas do infile, então simultaneamente escreverá cada linha para outfile e a enviará para o segundo cat .

No segundo cat , a entrada padrão lê primeiro do canal (o conteúdo do infil), depois lê do infile2, escrevendo cada linha para outfile2. Depois de executar isso, outfile será uma cópia do infile, e outfile2 conterá infile seguido por infile2.

Finalmente, você realmente faz algo muito semelhante ao seu exemplo usando o redirecionamento "here string" (somente família bash) e backticks:

grep blah <<<'ls'

dará o mesmo resultado que

ls | grep blah

Mas acho que a versão de redirecionamento primeiro lerá toda a saída de ls em um buffer (na memória) e, em seguida, alimentará esse buffer para grep uma linha por vez, enquanto a versão canalizada tomará cada linha de ls como emerge e passa essa linha para grep.

    
por user319857 24.08.2014 / 00:24
1

Eu encontrei um problema com isso em C hoje. Essencialmente, o Pipe tem semânticas diferentes para redirecionamentos, mesmo quando enviados para stdin . Realmente eu acho que, dadas as diferenças, os pipes devem ir a algum lugar diferente de stdin , de modo que stdin e vamos chamá-lo de stdpipe (para fazer um diferencial arbitrário) podem ser tratados de maneiras diferentes.

Considere isso. Quando o piping de uma saída do programa para outro fstat parece retornar zero como st_size apesar de ls -lha /proc/{PID}/fd mostrar que existe um arquivo. Ao redirecionar um arquivo, este não é o caso (pelo menos no debian wheezy , stretch e jessie vanilla e ubuntu 14.04 , 16.04 vanilla.

Se você cat /proc/{PID}/fd/0 com um redirecionamento poderá repetir para ler quantas vezes quiser. Se você fizer isso com um pipe, você notará que na segunda vez que executar a tarefa consecutivamente, não obterá a mesma saída.

    
por MrMesees 26.10.2017 / 18:17
0

Para adicionar às outras respostas, também há diferenças semânticas sutis - por exemplo, pipes fecham mais facilmente que os redirecionamentos:

seq 5 | (head -n1; head -n1)                # just 1
seq 5 > tmp5; (head -n1; head -n1) < tmp5   # 1 and 2
seq 5 | (read LINE; echo $LINE; head -n1)   # 1 and 2

No primeiro exemplo, quando a primeira chamada para head termina, fecha o canal e seq termina, portanto, não há entrada disponível para o segundo head .

No segundo exemplo, head consome a primeira linha, mas quando fecha seu próprio stdin pipe , o arquivo permanece aberto para a próxima chamada a ser usada.

O terceiro exemplo mostra que, se usarmos read para evitar o fechamento do canal, ele ainda estará disponível no subprocesso.

Assim, o "fluxo" é a coisa pela qual nós derivamos dados (stdin etc), e é o mesmo em ambos os casos, mas o pipe conecta fluxos de dois processos, onde um redirecionamento conecta fluxos entre um processo e um arquivo , então você pode ver a fonte das semelhanças e diferenças.

P.S. Se você está tão curioso e / ou surpreso com esses exemplos quanto eu estava, você pode se aprofundar usando trap para ver como os processos se resolvem, por exemplo:

(trap 'echo seq EXITed >&2' EXIT; seq 5) | (trap 'echo all done' EXIT; (trap 'echo first head exited' EXIT; head -n1)
echo '.'
(trap 'echo second head exited' EXIT; head -n1))

Às vezes, o primeiro processo é fechado antes que 1 seja impresso, às vezes depois.

Também achei interessante usar exec <&- para fechar o fluxo do redirecionamento para aproximar o comportamento do canal (embora com um erro):

seq 5 > tmp5
(trap 'echo all done' EXIT
(trap 'echo first head exited' EXIT; head -n1)
echo '.'
exec <&-
(trap 'echo second head exited' EXIT; head -n1)) < tmp5'
    
por Julian de Bhal 05.06.2018 / 02:54

Tags