Por que a substituição do processo resulta em um arquivo chamado / dev / fd / 63, que é um canal?

40

Estou tentando entender pipes nomeados no contexto deste exemplo em particular.

Digito <(ls -l)no meu terminal e recebo a saída como bash: /dev/fd/63: Permission denied,.

Se eu digitar cat <(ls -l), poderá ver o conteúdo do diretório. Se eu substituir o catpor echo, acho que recebo o nome do terminal (ou é?).

echo <(ls -l)dá a saída como /dev/fd/63.

Além disso, este exemplo de saída não está claro para mim.

ls -l <(echo "Whatever")
lr-x------ 1 root root 64 Sep 17 13:18 /dev/fd/63 -> pipe:[48078752]

No entanto, se eu der, ls -l <()ele me lista o conteúdo do diretório.

O que está acontecendo no caso do pipe nomeado?

Ramesh
fonte

Respostas:

37

Quando você faz isso <(some_command), seu shell executa o comando entre parênteses e substitui a coisa toda por um descritor de arquivo conectado ao stdout do comando. O mesmo /dev/fd/63acontece com um canal que contém a saída da sua chamada ls.

Quando você <(ls -l)recebe um Permission deniederro, porque toda a linha é substituída pelo canal, tentando efetivamente chamar /dev/fd/63como um comando, que não é executável.

No seu segundo exemplo, cat <(ls -l)torna-se cat /dev/fd/63. Conforme o gato lê os arquivos dados como parâmetros, você obtém o conteúdo. echopor outro lado, apenas exibe seus parâmetros "como estão".

O último caso que você tem <()é simplesmente substituído por nada, pois não há comando. Mas isso não é consistente entre as conchas, no zsh você ainda recebe um cachimbo (embora vazio).

Resumo : <(command)permite usar a saída de um comando, onde você normalmente precisaria de um arquivo.

Edit: como Gilles aponta, este não é um pipe nomeado, mas um pipe anônimo. A principal diferença é que ela existe apenas enquanto o processo estiver em execução, enquanto um pipe nomeado (criado, por exemplo, com mkfifo) permanecerá sem processos anexados a ele.

crater2150
fonte
5
mkfifocria apenas o canal nomeado, sem nenhum conteúdo. Então você precisa escrever para você mesmo (por exemplo mkfifo mypipe; ls > mypipe). E sim, as gravações no canal serão bloqueadas até que algum processo seja lido no canal.
amigos estão dizendo sobre crater2150
6
Não há pipe nomeado aqui. /dev/fd/63é um tubo anônimo.
Gilles 'SO- stop being evil'
11
@ crater2150, @Gilles / dev / fd / 63 é realmente um pipe nomeado. Verifique isso com algo parecido file <(ls). O shell cria um canal anônimo, mas o descritor de arquivo reflete como um canal nomeado /dev/fd. Se fosse um canal anônimo, não teria um nome e não poderia ser aberto por um comando ao qual /dev/fd/63é passado.
rv
2
@rv Ainda é um tubo anônimo. O fato de existir um nome de arquivo que se refere a esse canal anônimo não o torna um canal nomeado: um canal nomeado é diferente, existe em algum lugar do sistema de arquivos, possui permissões e propriedade, etc. Entradas de /dev/fdpodem se referir a qualquer arquivo descritor, até canos e soquetes anônimos, soquetes de rede, segmentos de memória compartilhada, etc.
Gilles 'SO- stop be evil'
11
Por que é 63 , no entanto?
K3 --- rnc
-4

Você entende mal o lscomando e o redirecionamento. lslista os arquivos e diretórios fornecidos na linha de comando, não acredito que aceite qualquer entrada do stdin. Redirecionamento > >>e <são maneiras de usar um arquivo para fornecer entrada e coletar saída.

ruibarbo
fonte
11
Não há redirecionamento de um arquivo aqui. <(…)é uma substituição de processo.
Gilles 'SO- stop be evil'
11
@IMSoP - como disse Gilles - não é um canal nomeado - é um canal anônimo. É x|ypraticamente o mesmo e quase idêntico ao [num]<<REDIRECTde algumas conchas. Onde difere é a substituição literal do shell do link fd - /dev/fd/63e etc e o que ele faz - ou não - com stdin. Faça echo | readlink /dev/fd/0e veja por si mesmo.
mikeserv
11
@IMSoP - esse é um devlink - um arquivo especial. você pode fazer o mesmo com qualquer descritor de arquivo na maioria dos sistemas linux - mesmo típico |pipes, embora eu não ateste o comportamento em outro lugar. Eu entendo de onde você está, mas um pipe nomeado é uma coisa separada em si - é uma referência do sistema de arquivos a um pipe no kernel - uma referência regular do sistema de arquivos, não um arquivo de dispositivo.
mikeserv
11
@mikeserv Curiosamente, o manual do Bash menciona que ele funcionará em sistemas sem a /dev/fd/*criação de um pipe nomeado em outro lugar. Mas entendo que /dev/fd/*ele próprio é um mecanismo diferente de um pipe nomeado propriamente dito. Aliás, a descrição da Wikipedia poderia ter uma explicação para essa distinção.
IMSoP
11
@mikeserv De acordo com outras referências que encontrei, é mais simples que isso: se /dev/fd/*não estiver disponível, o bash criará um pipe nomeado /tmpe o usará para substituição de processos. Não me parece tão estranho, apenas disponibilizando a funcionalidade no maior número possível de ambientes.
IMSoP 18/09/2014