Различный вывод из двух программ без временных файлов

145

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

Можно ли их выводить без предварительной записи во временные файлы?

Verhogen
источник

Ответы:

211

Используйте <(command)для передачи вывода одной команды другой программе, как если бы это было имя файла. Bash направляет вывод программы в канал и передает имя файла подобно /dev/fd/63внешней команде.

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

Точно так же вы можете использовать, >(command)если вы хотите передать что-то в команду.

На справочной странице Bash это называется «Замена процесса».

Джон Кугельман
источник
1
Один из недостатков, о которых следует знать, это то, что если ./a или ./b не удается, вызывающая сторона не узнает об этом.
Александр Погребняк
5
ОП пометил вопрос bash, но для записи это не работает ни в одной другой оболочке. Это расширение bash для стандарта утилит 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пакетом на большинстве систем.
Тим Визе
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)

Надеюсь, что это было полезно.

darrenthatcher
источник
0

Для zsh использование =(command)автоматически создает временный файл и заменяет =(command)путь к самому файлу. При нормальной $(command)замене процесса заменяется выводом команды.

Эта функция zsh очень полезна и может использоваться для сравнения выходных данных двух команд с использованием инструмента сравнения, например Beyond Compare:

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

Для Beyond Compare обратите внимание, что вы должны использовать bcompвышеперечисленное (вместо bcompare), поскольку bcompзапускает сравнение и ожидает его завершения. Если вы используетеbcompare , это запускает сравнение и сразу же завершает работу, из-за чего временные файлы, созданные для хранения вывода команд, исчезают.

Узнайте больше здесь: http://zsh.sourceforge.net/Intro/intro_7.html

Также обратите внимание на это:

Обратите внимание, что оболочка создает временный файл и удаляет его после завершения команды.

и следующее, в котором разница между $(...)и =(...):

Если вы прочитаете справочную страницу zsh, вы можете заметить, что <(...) - это другая форма подстановки процесса, аналогичная = (...). Между ними есть важное различие. В случае <(...) оболочка создает именованный канал (FIFO) вместо файла. Это лучше, так как не заполняет файловую систему; но это работает не во всех случаях. Фактически, если бы мы заменили = (...) на <(...) в приведенных выше примерах, все они перестали бы работать, кроме fgrep -f <(...). Вы не можете редактировать канал или открывать его как почтовую папку; Однако у fgrep нет проблем с чтением списка слов из канала. Вы можете спросить, почему не работает diff <(foo), так как foo | diff - барные работы; это связано с тем, что diff создает временный файл, если он замечает, что одним из его аргументов является -, а затем копирует свой стандартный ввод во временный файл.

Ашутош Джиндал
источник