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.