Різний вихід з двох програм без тимчасових файлів


145

Скажіть, у мене занадто програми aі bщо я можу запускатись із ./aта ./b.

Чи можна відрізняти їх результати без попереднього запису до тимчасових файлів?


Відповіді:


211

Використовуйте <(command)для передачі виводу однієї команди іншій програмі так, ніби це ім'я файлу. Bash передає вихід програми в трубу і передає ім'я файлу, як /dev/fd/63у зовнішню команду.

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

Аналогічно ви можете використовувати, >(command)якщо хочете щось передавати в команду.

Це називається "Заміна процесу" на сторінці "Баш".


1
Одним із недоліків, який слід пам’ятати, є те, що якщо ./a або ./b не вдасться, абонент цього не дізнається.
Олександр Погребняк

5
ОП позначає башти питань, але для запису це не працює в будь-якій іншій оболонці. Це баш-розширення до стандарту утиліти Posix.
DigitalRoss

5
Я спробував це рішення з програмою Java і отримав цю помилку: -bash: syntax error near unexpected token ('. Я спробував знову без дужок і дістався -bash: java: No such file or directory. Це не працює, якщо команда має параметри?
styfle

1
@DigitalRoss - рішення можна поширити на інші оболонки за допомогою псевдоніма. У Tcsh наступне неподобство роботи: alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'. (Тоді для прикладу: diffcmd "ls" "ls -a").
Пол Лінч

Для тих, хто блукає поза Google, це також працює під zsh. (Крім того, якщо вам потрібно ввести вхід на щось, що викликає fseek, zsh пропонує те, =(./a)що можна використовувати ідентично, <(./a)але використовує тимчасовий файл під кришкою, який zsh видалить для вас.)
ssokolow

26

Додавши до обох відповідей, якщо ви хочете бачити порівняння, використовуйте vimdiff:

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

Щось на зразок цього:

введіть тут опис зображення


vimdiffстворює красиві, розумні та інтерактивні погляди на порівняння різниць. Схоже, він постачається з vimпакетом для більшості систем.
Tim Visée

vimdiffтакож показано не тільки рядок, який відрізняється, але й конкретний текстовий фрагмент, який відрізняється.
Антон Тарасенко


15

Для будь-кого, хто цікавиться, ось як ви виконуєте підстановку процесу за допомогою оболонки Fish :

Bash:

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

Риба:

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

На жаль, реалізація риби в даний час є недостатньою ; риба буде або висіти, або використовувати тимчасовий файл на диску. Ви також не можете використовувати psub для виведення з вашої команди.


Наразі це не працює належним чином у рибі. Якщо вихід програм більше одного BUFSIZ, команда буде висіти. (або риба фактично буде використовувати тимчасовий файл на диску)
Еван Бенн

7

Додамо трохи більше до вже хороших відповідей (допомогли мені!):

Команда dockerвидає свою допомогу STD_ERR(тобто дескриптор файлу 2)

Я хотів би бачити , якщо docker attachі docker attach --helpдав той же результат

$ docker attach

$ docker attach --help

Щойно набравши ці дві команди, я зробив наступне:

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

!! - це те саме, що! -1, що означає виконати команду 1 перед цією - останньою командою

! -2 означає запустити команду дві перед цією

2> & 1 означає надіслати файл file_descriptor 2 (STD_ERR) на те саме місце, що і файл file_descriptor 1 (STD_OUT)

Сподіваюся, що це принесло користь.


0

Для zsh, використання =(command)автоматично створює тимчасовий файл і замінює =(command)шлях до самого файлу. При звичайній Процес заміщення $(command)замінюється результатом команди.

Ця функція zsh дуже корисна і може бути використана так, щоб порівняти вихід двох команд за допомогою інструмента "diff", наприклад Beyond Порівняти:

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

Для "Більше порівняння" зауважте, що ви повинні використовувати bcompдля вищезазначеного (замість bcompare), оскільки bcompзапускає порівняння і чекає його завершення. Якщо ви використовуєте bcompare, це запускає порівняння і негайно виходить із-за чого тимчасові файли, створені для зберігання виводу команд, зникають.

Детальніше читайте тут: http://zsh.sourceforge.net/Intro/intro_7.html

Також зауважте це:

Зауважте, що оболонка створює тимчасовий файл і видаляє його, коли команда закінчена.

і наступне, що є різницею між $(...)та =(...):

Якщо ви читаєте чоловічу сторінку zsh, ви можете помітити, що <(...) - це ще одна форма заміни процесу, яка схожа на = (...). Існує важлива різниця між ними. У випадку <(...) оболонка створює названу трубу (FIFO) замість файлу. Це краще, оскільки воно не заповнює файлову систему; але це працює не у всіх випадках. Насправді, якби ми замінили = (...) на <(...) у наведених вище прикладах, усі вони перестали б працювати, за винятком fgrep -f <(...). Ви не можете редагувати трубу або відкривати її як поштову папку; fgrep, однак, не має проблем із читанням списку слів із труби. Вам може бути цікаво, чому смуга diff <(foo) не працює, оскільки foo | різні роботи; це тому, що diff створює тимчасовий файл, якщо він помічає, що одним з його аргументів є -, а потім копіює його стандартний вхід у тимчасовий файл.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.