Uscita diff da due programmi senza file temporanei


Risposte:


211

Utilizzare <(command)per passare l'output di un comando a un altro programma come se fosse un nome file. Bash invia l'output del programma a una pipe e passa un nome di file simile /dev/fd/63al comando esterno.

diff <(./a) <(./b)

Allo stesso modo puoi usare >(command)se vuoi inserire qualcosa in un comando.

Questo si chiama "Sostituzione del processo" nella pagina man di Bash.


1
Uno svantaggio da tenere presente è che se ./a o ./b fallisce, il chiamante non lo scoprirà.
Alexander Pogrebnyak,

5
L'OP ha taggato la domanda bash, ma per la cronaca, questo non funziona in nessun'altra shell. È un'estensione bash dello standard di utilità Posix.
DigitalRoss,

5
Ho provato questa soluzione con un programma Java e ottenuto questo errore: -bash: syntax error near unexpected token ('. Ho provato di nuovo senza parentesi e ho ottenuto -bash: java: No such file or directory. Non funziona se il comando ha parametri?
styfle,

1
@DigitalRoss - La soluzione può essere estesa ad altre shell usando un alias. In tcsh, il seguente brutture funziona: alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'. (Quindi per esempio: diffcmd "ls" "ls -a").
Paul Lynch,

Per chiunque vada fuori da Google, questo funziona anche sotto zsh. (Inoltre, se hai bisogno di alimentare l'input in qualcosa che chiama fseek, zsh offre =(./a)che può essere usato in modo identico <(./a)ma utilizza un file temporaneo sotto il cofano, che zsh eliminerà per te.)
ssokolow

26

Aggiungendo a entrambe le risposte, se si desidera vedere un confronto affiancato, utilizzare vimdiff:

vimdiff <(./a) <(./b)

Qualcosa come questo:

inserisci qui la descrizione dell'immagine


vimdiffcrea viste di confronto delle differenze belle, intelligenti e interattive. Sembra venire con il vimpacchetto sulla maggior parte dei sistemi.
Tim Visée,

vimdiffmostra anche non solo la linea che differisce, ma anche il frammento di testo specifico che differisce.
Anton Tarasenko,


15

Per chiunque sia curioso, questo è il modo in cui esegui la sostituzione del processo usando la shell di pesce :

bash:

diff <(./a) <(./b)

Pesce:

diff (./a | psub) (./b | psub)

Purtroppo l'implementazione nei pesci è attualmente carente ; fish si bloccherà o utilizzerà un file temporaneo sul disco. Inoltre, non è possibile utilizzare psub per l'output del comando.


Questo attualmente non funziona correttamente nei pesci. Se l'output dei programmi è maggiore di un BUFSIZ, il comando si bloccherà. (o fish utilizzerà solo un file temporaneo su disco)
Evan Benn,

7

Aggiungendo un po 'di più alle già buone risposte (mi ha aiutato!):

Il comando dockerfornisce il suo aiuto a STD_ERR(cioè il descrittore di file 2)

Volevo vedere se docker attache ho docker attach --helpdato lo stesso risultato

$ docker attach

$ docker attach --help

Dopo aver digitato quei due comandi, ho fatto quanto segue:

$ diff <(!-2 2>&1) <(!! 2>&1)

!! è lo stesso di! -1 che significa eseguire il comando 1 prima di questo - l'ultimo comando

! -2 significa eseguire il comando due prima di questo

2> & 1 significa inviare output file_descriptor 2 (STD_ERR) nello stesso posto dell'output file_descriptor 1 (STD_OUT)

Spero che questo sia stato di qualche utilità.


0

Per zsh, l'utilizzo =(command)crea automaticamente un file temporaneo e lo sostituisce =(command)con il percorso del file stesso. Con la normale sostituzione del processo, $(command)viene sostituito con l' output del comando.

Questa funzione zsh è molto utile e può essere utilizzata in questo modo per confrontare l'output di due comandi utilizzando uno strumento diff, ad esempio Beyond Compare:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

Per Beyond Compare, tenere presente che è necessario utilizzare bcompquanto sopra (anziché bcompare) poiché bcompavvia il confronto e attende il completamento. Se lo usi bcompare, questo avvia il confronto ed esce immediatamente a causa della quale scompaiono i file temporanei creati per memorizzare l'output dei comandi.

Maggiori informazioni qui: http://zsh.sourceforge.net/Intro/intro_7.html

Notare anche questo:

Si noti che la shell crea un file temporaneo e lo elimina al termine del comando.

e la seguente che è la differenza tra $(...)e =(...):

Se leggi la pagina man di zsh, potresti notare che <(...) è un'altra forma di sostituzione del processo che è simile a = (...). C'è una differenza importante tra i due. Nel caso <(...), la shell crea una pipe denominata (FIFO) anziché un file. Questo è meglio, dal momento che non riempie il file system; ma non funziona in tutti i casi. In effetti, se avessimo sostituito = (...) con <(...) negli esempi sopra, tutti avrebbero smesso di funzionare tranne fgrep -f <(...). Non è possibile modificare una pipe o aprirla come una cartella di posta; fgrep, tuttavia, non ha problemi a leggere un elenco di parole da una pipe. Potresti chiederti perché la barra diff <(foo) non funziona, poiché foo | diff - bar funziona; questo perché diff crea un file temporaneo se nota che uno dei suoi argomenti è -, quindi copia l'input standard nel file temporaneo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.