Jednowierszowy z 2 plikami tmp (nie tym, czego chcesz) byłby:
foo | bar > file1.txt && baz | quux > file2.txt && diff file1.txt file2.txt
W przypadku basha możesz jednak spróbować:
diff <(foo | bar) <(baz | quux)
foo | bar | diff - <(baz | quux) # or only use process substitution once
Druga wersja będzie wyraźniej przypominać ci, które wejście było które, pokazując
-- /dev/stdin
vs. ++ /dev/fd/63
lub coś, zamiast dwóch ponumerowanych fds.
Nawet nazwany potok nie pojawi się w systemie plików, przynajmniej w systemach operacyjnych, w których bash może zaimplementować podstawianie procesów przy użyciu nazw plików, takich jak /dev/fd/63
uzyskanie nazwy pliku, którą polecenie może otworzyć i odczytać, aby faktycznie czytać z już otwartego deskryptora pliku ustawionego przez bash up przed wykonaniem polecenia. (tj. bash używa pipe(2)
przed rozwidleniem, a następnie dup2
przekierowuje z wyjścia quux
do deskryptora pliku wejściowego dla diff
, na fd 63.)
W systemie bez "magicznych" /dev/fd
lub /proc/self/fd
, bash może używać nazwanych potoków do implementacji podstawiania procesów, ale przynajmniej sam zarządzałby nimi, w przeciwieństwie do plików tymczasowych, a twoje dane nie zostałyby zapisane w systemie plików.
Możesz sprawdzić, jak bash implementuje podstawianie za pomocą, echo <(true)
aby wypisać nazwę pliku zamiast czytać z niego. Drukuje /dev/fd/63
na typowym systemie Linux. Aby uzyskać więcej informacji na temat dokładnie tego, jakich wywołań systemowych używa bash, to polecenie w systemie Linux będzie śledzić wywołania systemowe plików i deskryptorów plików
strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
Bez basha możesz stworzyć nazwaną potokę . Służy -
do mówienia, diff
aby odczytać jedno wejście ze STDIN i użyj nazwanego potoku jako drugiego:
mkfifo file1_pipe.txt
foo|bar > file1_pipe.txt && baz | quux | diff file1_pipe.txt - && rm file1_pipe.txt
Zauważ, że możesz przesłać tylko jedno wyjście do wielu wejść za pomocą polecenia tee:
ls *.txt | tee /dev/tty txtlist.txt
Powyższe polecenie wyświetla wyjście ls * .txt na terminal i wyprowadza je do pliku tekstowego txtlist.txt.
Ale dzięki podstawianiu procesów możesz użyć tee
do wprowadzenia tych samych danych do wielu potoków:
cat *.txt | tee >(foo | bar > result1.txt) >(baz | quux > result2.txt) | foobar
mkfifo a; cmd >a& cmd2|diff a -; rm a
pipeline1 | diff -u - <(pipeline2)
. Wtedy wynik będzie wyraźniej przypominał ci, które wejście było które, pokazując-- /dev/stdin
vs.++ /dev/fd/67
lub coś, zamiast dwóch ponumerowanych fds.foo <( pipe )
) procesu nie modyfikuje systemu plików. Fajka jest anonimowa ; nie ma nazwy w systemie plików . Powłoka używapipe
wywołania systemowego do jej utworzenia, a niemkfifo
. Służystrace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
do śledzenia wywołań systemowych plików i deskryptorów plików, jeśli chcesz się o tym przekonać. W systemie Linux/dev/fd/63
jest częścią/proc
wirtualnego systemu plików; automatycznie zawiera wpisy dla każdego deskryptora pliku i nie jest kopią zawartości. Więc nie możesz nazwać tego „plikiem tymczasowym”, chyba że sięfoo 3<bar.txt
liczyW bash możesz użyć podpowłok, aby wykonać potoki poleceń indywidualnie, zamykając potok w nawiasach. Możesz następnie poprzedzić je <, aby utworzyć anonimowe potoki nazwane, które następnie możesz przekazać do diff.
Na przykład:
Anonimowe potoki nazwane są zarządzane przez bash, więc są tworzone i niszczone automatycznie (w przeciwieństwie do plików tymczasowych).
źródło
Niektórzy ludzie wchodzący na tę stronę mogą szukać różnicy wiersz po wierszu, dla którego
comm
lubgrep -f
należy go użyć zamiast tego.Należy zwrócić uwagę na to, że we wszystkich przykładach odpowiedzi różnice nie zaczną się tak naprawdę, dopóki oba strumienie nie zakończą się. Przetestuj to na przykład:
Jeśli jest to problem, możesz wypróbować sd (stream diff), który nie wymaga sortowania (tak jak w przypadku
comm
) ani zastępowania procesu, jak w powyższych przykładach, jest o rząd wielkości szybszy niżgrep -f
i obsługuje nieskończone strumienie.Przykład testowy, który proponuję, byłby napisany w następujący sposób
sd
:Ale różnica polega na tym,
seq 100
że od razu się to zmieniseq 10
. Zwróć uwagę, że jeśli jednym ze strumieni jest atail -f
, nie można wykonać różnicy z podstawieniem procesu.Oto post na blogu, który napisałem o różnicowaniu strumieni na terminalu, który wprowadza
sd
.źródło