Digamos que eu também tenha programas a
e b
que possa executar com ./a
e ./b
.
É possível diferenciar suas saídas sem primeiro gravar em arquivos temporários?
Digamos que eu também tenha programas a
e b
que possa executar com ./a
e ./b
.
É possível diferenciar suas saídas sem primeiro gravar em arquivos temporários?
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.
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.
-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
:
vimdiff <(./a) <(./b)
Algo assim:
vimdiff
cria visualizações de comparação de diferenças bonitas, inteligentes e interativas. Parece vir com o vim
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) :
mkfifo a_fifo b_fifo
./a > a_fifo &
./b > b_fifo &
diff a_fifo b_fifo
... mas a solução de John Kugelman é muito mais limpa.
rm a_fifo b_fifo
.
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.
Adicionando um pouco mais às já boas respostas (me ajudaram!):
O comando docker
envia sua ajuda para STD_ERR
(ou seja, descritor de arquivo 2)
Eu queria ver se docker attach
e docker 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.
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 bcomp
o acima (em vez de bcompare
), pois bcomp
inicia 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.
Leia mais aqui: http://zsh.sourceforge.net/Intro/intro_7.html
Observe também o seguinte:
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.