Porównaj dane wyjściowe z dwóch programów bez plików tymczasowych

Odpowiedzi:

211

Służy <(command)do przekazywania wyników jednego polecenia do innego programu, tak jakby to była nazwa pliku. Bash przesyła dane wyjściowe programu do potoku i przekazuje nazwę pliku, taką jak /dev/fd/63do polecenia zewnętrznego.

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

Podobnie możesz użyć, >(command)jeśli chcesz przesłać coś do polecenia.

Na stronie podręcznika systemowego Bash jest to nazywane „Zastępowaniem procesów”.

John Kugelman
źródło
1
Jedną wadą, o której należy pamiętać, jest to, że jeśli ./a lub ./b zawiedzie, dzwoniący nie dowie się o tym.
Alexander Pogrebnyak
5
OP oznaczył bash pytania, ale dla przypomnienia, nie działa to w żadnej innej powłoce. Jest to rozszerzenie bash standardu narzędziowego Posix.
DigitalRoss
5
Próbowałem to rozwiązanie z programem Java i mam ten błąd: -bash: syntax error near unexpected token ('. Spróbowałem ponownie bez nawiasów i otrzymałem -bash: java: No such file or directory. Czy to nie działa, jeśli polecenie ma parametry?
styfle
1
@DigitalRoss - Rozwiązanie można rozszerzyć na inne powłoki za pomocą aliasu. W tcsh następujące brzydota działa: alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'. (Na przykład: diffcmd "ls" "ls -a").
Paul Lynch
Dla każdego, kto błąka się poza Google, działa to również pod zsh. (Ponadto, jeśli chcesz wprowadzić dane wejściowe do czegoś, co wywołuje fseek, zsh oferuje, =(./a)które mogą być używane identycznie, <(./a)ale używają tymczasowego pliku pod maską, który zsh usunie za ciebie.)
ssokolow Stycznia
26

Dodając do obu odpowiedzi, jeśli chcesz zobaczyć porównanie obok siebie, użyj vimdiff:

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

Coś takiego:

wprowadź opis obrazu tutaj

złamana stopa
źródło
vimdifftworzy piękne, inteligentne i interaktywne widoki porównujące różnice. Wydaje się, że jest dostarczany z vimpakietem w większości systemów.
Tim Visée
vimdiffpokazuje również nie tylko różniący się wiersz, ale także specyficzny fragment tekstu, który się różni.
Anton Tarasenko
15

Dla każdego, kto jest ciekawy, w ten sposób wykonujesz podstawianie procesów przy użyciu skorupy ryby :

Grzmotnąć:

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

Ryba:

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

Niestety implementacja u ryb jest obecnie niewystarczająca ; fish albo zawiesi się, albo użyje tymczasowego pliku na dysku. Nie możesz również użyć psub do wyjścia z polecenia.

James McMahon
źródło
Obecnie nie działa to poprawnie w przypadku ryb. Jeśli wyjście programów jest większe niż jeden BUFSIZ, polecenie zawiesi się. (lub ryba po prostu użyje pliku tymczasowego na dysku)
Evan Benn,
7

Dodanie trochę więcej do już dobrych odpowiedzi (pomogło mi!):

Polecenie dockerwyświetla pomoc do STD_ERR(tj. Deskryptor pliku 2)

Chciałem zobaczyć, czy docker attachi docker attach --helpdała taki sam efekt

$ docker attach

$ docker attach --help

Po wpisaniu tych dwóch poleceń wykonałem następujące czynności:

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

!! jest tym samym, co! -1, co oznacza uruchomienie polecenia 1 przed tym - ostatnim poleceniem

! -2 oznacza uruchomienie polecenia dwa przed tym

2> & 1 oznacza wysyłanie wyjścia file_descriptor 2 (STD_ERR) do tego samego miejsca, co wyjście file_descriptor 1 (STD_OUT)

Mam nadzieję, że to się przydało.

darrenthatcher
źródło
0

W przypadku zsh użycie =(command)automatycznie tworzy plik tymczasowy i zastępuje =(command)ścieżką samego pliku. Przy normalnym zastępowaniu procesu, $(command)jest zastępowane danymi wyjściowymi polecenia.

Ta funkcja zsh jest bardzo przydatna i może być używana w ten sposób do porównania wyników dwóch poleceń za pomocą narzędzia porównywania, na przykład Beyond Compare:

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

W przypadku Beyond Compare należy pamiętać, że należy użyć bcomppowyższego (zamiast bcompare), ponieważ bcompuruchamia porównanie i czeka na zakończenie. Jeśli używasz bcompare, uruchamia porównanie i natychmiast kończy pracę, dzięki czemu znikają pliki tymczasowe utworzone do przechowywania danych wyjściowych poleceń.

Przeczytaj więcej tutaj: http://zsh.sourceforge.net/Intro/intro_7.html

Zwróć również uwagę na to:

Zauważ, że powłoka tworzy plik tymczasowy i usuwa go po zakończeniu polecenia.

a następujące, które są różnicą między $(...)i =(...):

Jeśli przeczytasz stronę podręcznika zsh, możesz zauważyć, że <(...) jest inną formą podstawiania procesu, która jest podobna do = (...). Jest między nimi ważna różnica. W przypadku <(...) powłoka tworzy nazwany potok (FIFO) zamiast pliku. To jest lepsze, ponieważ nie wypełnia systemu plików; ale to nie działa we wszystkich przypadkach. W rzeczywistości, gdybyśmy w powyższych przykładach zamienili = (...) na <(...), wszystkie z nich przestałyby działać z wyjątkiem fgrep -f <(...). Nie możesz edytować potoku ani otwierać go jako folderu poczty; fgrep nie ma jednak problemu z odczytaniem listy słów z potoku. Możesz się zastanawiać, dlaczego diff <(foo) bar nie działa, ponieważ foo | diff - bar działa; Dzieje się tak, ponieważ diff tworzy plik tymczasowy, jeśli zauważy, że jednym z jego argumentów jest -, a następnie kopiuje swoje standardowe wejście do pliku tymczasowego.

Ashutosh Jindal
źródło