Uma boa maneira de entender a diferença entre eles é experimentar um pouco na linha de comando. Apesar da semelhança visual no uso do <
personagem, ele faz algo muito diferente de um redirecionamento ou canal.
Vamos usar o date
comando para testar.
$ date | cat
Thu Jul 21 12:39:18 EEST 2011
Este é um exemplo inútil, mas mostra que cat
aceitou a saída de date
no STDIN e cuspiu de volta. Os mesmos resultados podem ser alcançados pela substituição do processo:
$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011
No entanto, o que aconteceu nos bastidores foi diferente. Em vez de receber um fluxo STDIN, cat
foi realmente transmitido o nome de um arquivo que ele precisava para abrir e ler. Você pode ver esta etapa usando em echo
vez de cat
.
$ echo <(date)
/proc/self/fd/11
Quando o gato recebeu o nome do arquivo, ele leu o conteúdo do arquivo para nós. Por outro lado, echo apenas nos mostrou o nome do arquivo que foi passado. Essa diferença se torna mais óbvia se você adicionar mais substituições:
$ cat <(date) <(date) <(date)
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
$ echo <(date) <(date) <(date)
/proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13
É possível combinar a substituição do processo (que gera um arquivo) e o redirecionamento de entrada (que conecta um arquivo ao STDIN):
$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011
Parece praticamente o mesmo, mas desta vez o gato recebeu o fluxo STDIN em vez de um nome de arquivo. Você pode ver isso tentando com o eco:
$ echo < <(date)
<blank>
Como o eco não lê STDIN e nenhum argumento foi passado, não obtemos nada.
Canais e redirecionamentos de entrada direcionam o conteúdo para o fluxo STDIN. A substituição de processo executa os comandos, salva sua saída em um arquivo temporário especial e passa o nome do arquivo no lugar do comando. Qualquer que seja o comando que você esteja usando, trata-o como um nome de arquivo. Observe que o arquivo criado não é um arquivo comum, mas um canal nomeado que é removido automaticamente quando não é mais necessário.
[[ -p <(date) ]] && echo true
. Isso produztrue
quando eu o executo com o bash 4.4 ou 3.2.Suponho que você esteja falando
bash
ou sobre algum outro shell avançado, porque o shell posix não possui substituição de processo .bash
relatórios da página de manual:Em outras palavras, e de um ponto de vista prático, você pode usar uma expressão como a seguinte
como um nome de arquivo para outros comandos que requerem um arquivo como parâmetro. Ou você pode usar o redirecionamento para esse arquivo:
Voltando à sua pergunta, parece-me que a substituição de processo e os tubos não têm muito em comum.
Se você deseja canalizar em seqüência a saída de vários comandos, use um dos seguintes formulários:
mas você também pode usar o redirecionamento na substituição do processo
finalmente, se
command3
aceita um parâmetro de arquivo (em substituição de stdin)fonte
Aqui estão três coisas que você pode fazer com a substituição do processo que são impossíveis de outra maneira.
Várias entradas de processo
Simplesmente não há como fazer isso com tubos.
Preservando o STDIN
Digamos que você tenha o seguinte:
E você deseja executá-lo diretamente. O seguinte falha miseravelmente. O Bash já está usando STDIN para ler o script, portanto, outras entradas são impossíveis.
Mas dessa maneira funciona perfeitamente.
Substituição do processo de saída
Observe também que a substituição de processo também funciona da outra maneira. Então você pode fazer algo assim:
Esse é um exemplo um pouco complicado, mas ele envia stdout para
/dev/null
, enquanto canaliza stderr para um script sed para extrair os nomes dos arquivos para os quais um erro "Permissão negada" foi exibido e, em seguida, envia OS resultados para um arquivo.Observe que o primeiro comando e o redirecionamento stdout estão entre parênteses ( subshell ), para que apenas o resultado do comando THAT seja enviado para
/dev/null
e não mexa com o restante da linha.fonte
diff
exemplo, você pode querer se preocupar com o caso em que ocd
pode falhar:diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls)
.Se um comando pegar uma lista de arquivos como argumentos e processá-los como entrada (ou saída, mas não comumente), cada um desses arquivos poderá ser um pipe nomeado ou pseudo-arquivo / dev / fd fornecido de forma transparente pela subscrição do processo:
Isso irá "canalizar" a saída dos três comandos para classificar, pois a classificação pode levar uma lista de arquivos de entrada na linha de comando.
fonte
<()
, como muitos recursos avançados do shell, era originalmente um recurso do ksh e foi adotado pelo bash e pelo zsh.psub
é especificamente um recurso de peixe, nada a ver com o POSIX.Deve-se observar que a substituição do processo não se limita ao formulário
<(command)
, que usa a saídacommand
como um arquivo. Pode estar no formato>(command)
que alimenta um arquivo como entradacommand
também. Isso também é mencionado na citação do manual do bash na resposta do @ enzotib.Para o
date | cat
exemplo acima, um comando que usa a substituição de processo do formulário>(command)
para obter o mesmo efeito seria,Observe que o
>
antes>(cat)
é necessário. Isso pode ser novamente ilustrado claramenteecho
como na resposta de @ Caleb.Portanto, sem o extra
>
,date >(cat)
seria o mesmodate /dev/fd/63
que imprimirá uma mensagem para stderr.Suponha que você tenha um programa que apenas use nomes de arquivos como parâmetros e não processe
stdin
oustdout
. Usarei o script simplificado demaispsub.sh
para ilustrar isso. O conteúdo depsub.sh
éBasicamente, ele testa se ambos os seus argumentos são arquivos (não necessariamente arquivos regulares) e, se esse for o caso, escreva o primeiro campo de cada linha
"$1"
para"$2"
usar o awk. Então, um comando que combina tudo o que foi mencionado até agora é,Isso imprimirá
e é equivalente a
mas o seguinte não funcionará, e temos que usar a substituição de processo aqui,
ou sua forma equivalente
Se
./psub.sh
também lerstdin
além do mencionado acima, esse formulário equivalente não existe e, nesse caso, não podemos usar nada em vez da substituição do processo (é claro que você também pode usar um pipe nomeado ou um arquivo temporário, mas isso é outro história).fonte