Use <(command)para passar a saída de um comando para outro programa como se fosse um nome de arquivo. O Bash canaliza a saída do programa para um canal e passa um nome de arquivo como /dev/fd/63para o comando externo.
diff <(./a)<(./b)
Da mesma forma, você pode usar >(command)se quiser canalizar algo em um comando.
Isso é chamado de "Substituição de Processo" na página do manual do Bash.
Uma desvantagem é que, se ./a ou ./b falhar, o chamador não descobrirá isso.
Alexander Pogrebnyak
5
O OP marcou a questão como bash, mas, para constar, isso não funciona em nenhum outro shell. É uma extensão do bash para o padrão utilitário Posix.
DigitalRoss
5
Eu tentei esta solução com um programa Java e tenho esse erro: -bash: syntax error near unexpected token ('. Eu tentei novamente sem parênteses e consegui -bash: java: No such file or directory. Não funciona se o comando tiver parâmetros?
Styfle
1
@DigitalRoss - A solução pode ser estendida para outros shells usando um alias. Em tcsh, o seguinte feiúra funciona: alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'. (Então, por exemplo: diffcmd "ls" "ls -a").
Paul Lynch
Para quem está fora do Google, isso também funciona no zsh. (Além disso, se você precisa para entrada de alimentação em algo que as chamadas fseek, ofertas zsh =(./a)que podem ser usadas de forma idêntica para <(./a), mas usa um arquivo temporário sob o capô, que zsh vai apagar para você.)
ssokolow
26
Adicionando a ambas as respostas, se você quiser ver uma comparação lado a lado, use vimdiff:
É melhor remover os pipes nomeados depois de usá-los, com rm a_fifo b_fifo.
Franklin Yu
15
Para qualquer pessoa curiosa, é assim que você executa a substituição do processo usando o shell Fish :
Bash:
diff <(./a)<(./b)
Peixe:
diff (./a | psub)(./b | psub)
Infelizmente, a implementação em peixes é atualmente deficiente ; O peixe travará ou usará um arquivo temporário no disco. Você também não pode usar o psub para saída do seu comando.
Atualmente, isso não funciona corretamente em peixes. Se a saída dos programas for maior que um BUFSIZ, o comando será interrompido. (ou peixe vai realmente usar apenas um arquivo temporário no disco)
Evan Benn
7
Adicionando um pouco mais às já boas respostas (me ajudaram!):
O comando dockerenvia sua ajuda para STD_ERR(ou seja, descritor de arquivo 2)
Eu queria ver se docker attache docker attach --helpdeu a mesma saída
$ docker attach
$ docker attach --help
Depois de digitar esses dois comandos, fiz o seguinte:
$ diff <(!-2 2>&1) <(!! 2>&1)
!! é o mesmo que! -1, o que significa executar o comando 1 antes deste - o último comando
! -2 significa executar o comando dois antes deste
2> & 1 significa enviar a saída file_descriptor 2 (STD_ERR) para o mesmo local que a saída file_descriptor 1 (STD_OUT)
Para zsh, usar =(command)automaticamente cria um arquivo temporário e substitui =(command)o caminho do próprio arquivo. Com a Substituição de Processo normal, $(command)é substituída pela saída do comando.
Esse recurso zsh é muito útil e pode ser usado assim para comparar a saída de dois comandos usando uma ferramenta diff, por exemplo, Beyond Compare:
bcomp =(ulimit -Sa| sort)=(ulimit -Ha| sort)
Para Além da comparação, observe que você deve usar bcompo acima (em vez de bcompare), pois bcompinicia a comparação e aguarda a conclusão. Se você usar bcompare, isso inicia a comparação e sai imediatamente, devido ao qual os arquivos temporários criados para armazenar a saída dos comandos desaparecem.
Observe que o shell cria um arquivo temporário e o exclui quando o comando é concluído.
e o seguinte, que é a diferença entre $(...)e =(...):
Se você ler a página de manual do zsh, poderá notar que <(...) é outra forma de substituição de processo semelhante a = (...). Há uma diferença importante entre os dois. No caso <(...), o shell cria um pipe nomeado (FIFO) em vez de um arquivo. Isso é melhor, pois não preenche o sistema de arquivos; mas não funciona em todos os casos. De fato, se substituíssemos = (...) por <(...) nos exemplos acima, todos eles teriam parado de funcionar, exceto fgrep -f <(...). Você não pode editar um canal ou abri-lo como uma pasta de correio; O fgrep, no entanto, não tem problemas em ler uma lista de palavras de um pipe. Você pode se perguntar por que a barra diff <(foo) não funciona, pois foo | obras de difusão; isso ocorre porque o diff cria um arquivo temporário se perceber que um de seus argumentos é - e copia sua entrada padrão no arquivo temporário.
Respostas:
Use
<(command)
para passar a saída de um comando para outro programa como se fosse um nome de arquivo. O Bash canaliza a saída do programa para um canal e passa um nome de arquivo como/dev/fd/63
para o comando externo.Da mesma forma, você pode usar
>(command)
se quiser canalizar algo em um comando.Isso é chamado de "Substituição de Processo" na página do manual do Bash.
fonte
-bash: syntax error near unexpected token ('
. Eu tentei novamente sem parênteses e consegui-bash: java: No such file or directory
. Não funciona se o comando tiver parâmetros?alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'
. (Então, por exemplo: diffcmd "ls" "ls -a").fseek
, ofertas zsh=(./a)
que podem ser usadas de forma idêntica para<(./a)
, mas usa um arquivo temporário sob o capô, que zsh vai apagar para você.)Adicionando a ambas as respostas, se você quiser ver uma comparação lado a lado, use
vimdiff
:Algo assim:
fonte
vimdiff
cria visualizações de comparação de diferenças bonitas, inteligentes e interativas. Parece vir com ovim
pacote na maioria dos sistemas.vimdiff
também mostra não apenas a linha que difere, mas também o fragmento de texto específico que difere.Uma opção seria usar pipes nomeados (FIFOs) :
... mas a solução de John Kugelman é muito mais limpa.
fonte
rm a_fifo b_fifo
.Para qualquer pessoa curiosa, é assim que você executa a substituição do processo usando o shell Fish :
Bash:
Peixe:
Infelizmente, a implementação em peixes é atualmente deficiente ; O peixe travará ou usará um arquivo temporário no disco. Você também não pode usar o psub para saída do seu comando.
fonte
Adicionando um pouco mais às já boas respostas (me ajudaram!):
O comando
docker
envia sua ajuda paraSTD_ERR
(ou seja, descritor de arquivo 2)Eu queria ver se
docker attach
edocker attach --help
deu a mesma saída$ docker attach
$ docker attach --help
Depois de digitar esses dois comandos, fiz o seguinte:
$ diff <(!-2 2>&1) <(!! 2>&1)
!! é o mesmo que! -1, o que significa executar o comando 1 antes deste - o último comando
! -2 significa executar o comando dois antes deste
2> & 1 significa enviar a saída file_descriptor 2 (STD_ERR) para o mesmo local que a saída file_descriptor 1 (STD_OUT)
Espero que isso tenha sido útil.
fonte
Para zsh, usar
=(command)
automaticamente cria um arquivo temporário e substitui=(command)
o caminho do próprio arquivo. Com a Substituição de Processo normal,$(command)
é substituída pela saída do comando.Esse recurso zsh é muito útil e pode ser usado assim para comparar a saída de dois comandos usando uma ferramenta diff, por exemplo, Beyond Compare:
Para Além da comparação, observe que você deve usar
bcomp
o acima (em vez debcompare
), poisbcomp
inicia a comparação e aguarda a conclusão. Se você usarbcompare
, isso inicia a comparação e sai imediatamente, devido ao qual os arquivos temporários criados para armazenar a saída dos comandos desaparecem.Leia mais aqui: http://zsh.sourceforge.net/Intro/intro_7.html
Observe também o seguinte:
e o seguinte, que é a diferença entre
$(...)
e=(...)
:fonte