Однострочный файл с 2 файлами tmp (не то, что вы хотите) будет:
foo | bar > file1.txt && baz | quux > file2.txt && diff file1.txt file2.txt
Однако с помощью bash вы можете попробовать:
diff <(foo | bar) <(baz | quux)
foo | bar | diff - <(baz | quux)
Вторая версия будет более четко напоминать вам, какой вход был какой, показывая
-- /dev/stdin
vs. ++ /dev/fd/63
или что-то в этом роде, вместо двух пронумерованных файловых файлов.
В файловой системе не появится даже именованный канал, по крайней мере, в операционных системах, где bash может реализовать подстановку процессов, используя имена файлов, например, /dev/fd/63
получение имени файла, которое команда может открыть и прочитать, чтобы фактически прочитать из уже открытого файлового дескриптора, установленного bash вверх перед выполнением команды. (т.е. bash использует pipe(2)
перед fork, а затем dup2
для перенаправления с выводаquux
с дескриптора входного файла diff
на fd 63.)
В системе без «магических» /dev/fd
или/proc/self/fd
bash может использовать именованные каналы для реализации подстановки процессов, но он, по крайней мере, сам будет управлять ими, в отличие от временных файлов, и ваши данные не будут записаны в файловую систему.
Вы можете проверить, как bash реализует замену процесса, с помощью echo <(true)
печати имени файла вместо чтения из него. Он печатается /dev/fd/63
в типичной системе Linux. Или для получения более подробной информации о том, какие именно системные вызовы использует bash, эта команда в системе Linux будет отслеживать системные вызовы файлов и файловых дескрипторов.
strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
Без bash можно было бы создать именованный канал . Используйте, -
чтобы указать, что diff
нужно читать один ввод из STDIN и использовать именованный канал в качестве другого:
mkfifo file1_pipe.txt
foo|bar > file1_pipe.txt && baz | quux | diff file1_pipe.txt - && rm file1_pipe.txt
Обратите внимание, что вы можете направить только один выход на несколько входов с помощью команды tee:
ls *.txt | tee /dev/tty txtlist.txt
Приведенная выше команда отображает вывод ls * .txt на терминал и выводит его в текстовый файл txtlist.txt.
Но с заменой процесса вы можете использовать tee
для подачи одних и тех же данных в несколько конвейеров:
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)
. Тогда выходные данные будут более четко напоминать вам, какой вход был какой, показывая-- /dev/stdin
vs.++ /dev/fd/67
или что-то в этом роде, вместо двух пронумерованных файловых файлов.foo <( pipe )
) не изменяет файловую систему. Труба анонимная ; у него нет имени в файловой системе . Дляpipe
его создания оболочка использует системный вызов, а неmkfifo
. Используйтеstrace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
для отслеживания системных вызовов файлов и файловых дескрипторов, если хотите в этом убедиться. В Linux/dev/fd/63
это часть/proc
виртуальной файловой системы; в нем автоматически есть записи для каждого дескриптора файла, и он не является копией содержимого. Так что вы не можете называть это «временным файлом», если неfoo 3<bar.txt
считатьВ bash вы можете использовать подоболочки для индивидуального выполнения командных конвейеров, заключив конвейер в круглые скобки. Затем вы можете добавить к ним префикс <, чтобы создать анонимные именованные каналы, которые затем можно передать в diff.
Например:
Анонимные именованные каналы управляются bash, поэтому они создаются и уничтожаются автоматически (в отличие от временных файлов).
источник
Некоторые люди, попадающие на эту страницу, могут искать построчное сравнение, для которого
comm
илиgrep -f
должны использоваться вместо этого.Следует отметить, что во всех примерах ответов различие фактически не запускается, пока оба потока не закончатся. Проверьте это, например:
Если это проблема, вы можете попробовать sd (stream diff), который не требует сортировки (как это
comm
делает) или подстановки процессов, как в приведенных выше примерах, на порядки или величины быстрее, чемgrep -f
и поддерживает бесконечные потоки.Предлагаемый мной тестовый пример будет записан так
sd
:seq 100 | sd 'seq 10 20 && sleep 5 && seq 20 30'
Но разница в том,
seq 100
что сразу разобрались быseq 10
. Обратите внимание, что если один из потоков - это atail -f
, различие не может быть выполнено с заменой процесса.Вот пост блоге, который я написал о различии потоков на терминале, который представляет
sd
.источник