Como entender tubos

21

Quando eu apenas usei cachimbo no bash, não pensei mais sobre isso. Mas quando li algum exemplo de código C usando o pipe de chamada do sistema () junto com o fork (), pergunto-me como entender os pipes, incluindo os pipes anônimos e os pipes nomeados.

É ouvido frequentemente que "tudo no Linux / Unix é um arquivo". Gostaria de saber se um pipe é realmente um arquivo, de modo que uma parte que ele conecta grava no arquivo de pipe, e a outra parte lê do arquivo de pipe? Em caso afirmativo, onde é criado o arquivo de canal para um canal anônimo? Em / tmp, / dev ou ...?

No entanto, a partir de exemplos de pipes nomeados, também aprendi que o uso de pipes possui vantagem de desempenho de espaço e tempo em relação ao uso explícito de arquivos temporários, provavelmente porque não há arquivos envolvidos na implementação de pipes. Também os pipes parecem não armazenar dados como os arquivos. Então, duvido que um cachimbo seja realmente um arquivo.

Tim
fonte

Respostas:

23

Sobre sua pergunta de desempenho, os pipes são mais eficientes que os arquivos, porque não é necessário E / S de disco. Portanto, cmd1 | cmd2é mais eficiente do que cmd1 > tmpfile; cmd2 < tmpfile(isso pode não ser verdade se tmpfilefor feito backup em um disco RAM ou outro dispositivo de memória como pipe nomeado; mas se for um pipe nomeado, cmd1deverá ser executado em segundo plano, pois sua saída poderá bloquear se o pipe ficar cheio ) Se você precisar do resultado cmd1e ainda precisar enviar sua saída cmd2, deverá cmd1 | tee tmpfile | cmd2permitir cmd1e cmd2executar em paralelo evitando operações de leitura de disco cmd2.

Os pipes nomeados são úteis se muitos processos forem lidos / gravados no mesmo pipe. Eles também podem ser úteis quando um programa não foi projetado para usar stdin / stdout, pois sua E / S precisa de arquivos . Coloquei os arquivos em itálico, porque os pipes nomeados não são exatamente arquivos no ponto de vista de armazenamento, pois residem na memória e têm um tamanho de buffer fixo, mesmo se tiverem uma entrada do sistema de arquivos (para fins de referência). Outras coisas no UNIX têm entradas do sistema de arquivos sem serem arquivos: pense em /dev/nullou outras entradas em /devou /proc.

Como os pipes (nomeados e não nomeados) têm um tamanho de buffer fixo, as operações de leitura / gravação podem bloquear, fazendo com que o processo de leitura / gravação entre no estado IOWait. Além disso, quando você recebe um EOF ao ler de um buffer de memória? As regras sobre esse comportamento são bem definidas e podem ser encontradas no homem.

Uma coisa que você não pode fazer com os pipes (nomeados e não nomeados) é procurar nos dados. Como eles são implementados usando um buffer de memória, isso é compreensível.

Sobre "everything in Linux/Unix is a file", eu não concordo. Os pipes nomeados possuem entradas do sistema de arquivos, mas não são exatamente o arquivo. Os pipes sem nome não têm entradas do sistema de arquivos (exceto talvez em /proc). No entanto, a maioria das operações de E / S no UNIX é feita usando a função de leitura / gravação que precisa de um descritor de arquivo , incluindo pipe (e soquete) sem nome. Não acho que possamos dizer isso "everything in Linux/Unix is a file", mas certamente podemos dizer isso "most IO in Linux/Unix is done using a file descriptor".

jfg956
fonte
Obrigado! Os dois comandos estão conectados por um tubo em paralelo, em vez do segundo começa a ser executado após o primeiro término?
Tim
Sim, os 2 comandos são executados em paralelo. Se não estivessem e a 1ª saída fosse mais do que o buffer, ele seria bloqueado. Você pode experimentá-lo, executando cmd1 > fifoe cmd2 < fifoem 2 conchas diferentes, criando o pipe nomeado com mkfifo fifo.
Jfg956
Outro teste que você pode fazer é matar cmd2enquanto cmd1ainda está em execução: cmd1provavelmente irá parar de relatar uma mensagem de tubo quebrado.
Jfg956
Obrigado! o que você quer dizer com seria bloqueado? Se isso acontecer, significa que a data no fluxo após o bloco será perdida?
Tim
2
Os dados não são perdidos. Se o buffer do tubo estiver cheio, cmd1a gravação no tubo retornará apenas quando cmd2os dados forem lidos. Da mesma forma, cmd2a leitura de um canal será bloqueada se o buffer estiver vazio até que ele seja cmd1gravado no canal.
Jfg956
4

Dois dos fundamentos básicos da filosofia UNIX são:

  1. Criar pequenos programas que fazem uma coisa bem.
  2. e espere que a saída de cada programa se torne a entrada para outro
    programa ainda desconhecido.

    O uso de tubos permite que você aproveite os efeitos desses dois
    fundamentos de design para criar cadeias de comandos extremamente poderosas para alcançar o resultado desejado.

    A maioria dos programas de linha de comando que operam em arquivos também pode aceitar entrada na entrada padrão (entrada através do teclado) e saída na saída padrão (impressão na
    tela).

    Alguns comandos são projetados para operar apenas dentro de um canal, não podem operar diretamente em arquivos.

    por exemplo trcomando

  ls -C | tr 'a-z' 'A-Z'
    cmd1 | cmd2
  • Envia STDOUT de cmd1 para STDIN de cmd2 em vez da tela.

  • O STDERR não é encaminhado pelos tubos.

    Em suma, Pipes is character (|)pode conectar comandos.

    Qualquer comando que grava em STDOUT pode ser usado no lado esquerdo do pipe.

       ls - /etc | less 

    Qualquer comando que lê de STDIN pode ser usado no lado direito de um tubo.

       echo "test print" | lpr 

    Um canal tradicional é "sem nome" porque existe anonimamente e persiste apenas enquanto o processo estiver em execução. Um canal nomeado é persistente no sistema e existe além da vida útil do processo e deve ser excluído quando não estiver mais sendo usado. Os processos geralmente são anexados ao canal nomeado (geralmente aparecendo como um arquivo) para executar a comunicação entre processos (IPC).

fonte: http://en.wikipedia.org/wiki/Named_pipe

mr_eclair
fonte
3

Para complementar as outras respostas ...

stdin e stdout são descritores de arquivos e são lidos e gravados como se fossem arquivos. portanto, você pode fazer echo hi | grep hi, e ele substituirá o stdout do eco por um pipe e substituirá o stdin do grep pela outra extremidade deste pipe.

user606723
fonte
1

Tudo é um arquivo.

Se tomarmos a frase muito literalmente, acabaremos com o significado de "só temos arquivos e nada mais". Esta não é a interpretação correta, então o que é.

Quando dizemos "Tudo é um arquivo", não estamos dizendo que tudo está armazenado em um disco. Estamos dizendo que tudo parece um arquivo, pode ser lido, pode ser escrito.

No Unix, uma vez que um arquivo ou não-arquivo é aberto, ele pode ser tratado como um arquivo. No entanto, nem todos os arquivos suportam todas as operações. Por exemplo, alguns arquivos (que não são arquivos), não suportam a busca: eles devem ser lidos / gravados em sequência (isso é verdade para tubos e soquetes).

Tudo tem um nome de arquivo (em alguns sistemas: por exemplo, Debian Gnu / Linux e muitos outros Gnu / Linux).

  • Todos os arquivos abertos recebem um nome de arquivo. Vejo/proc/self/fd/…
  • Os soquetes de rede podem ser abertos com um nome de arquivo, /dev/tcp
    por exemplo,cat </dev/tcp/towel.blinkenlights.nl/23
ctrl-alt-delor
fonte
Essa última parte é válida apenas em sistemas com um /procsistema de arquivos e em sistemas (ou shells) que fornecem uma /dev/tcpestrutura de arquivos.
Kusalananda