Как мне объединить два именованных канала в один поток ввода в Linux

64

Используя |функцию pipe ( ) в Linux, я могу перенаправить стандартный ввод в один или несколько выходных потоков.

Я могу использовать, teeчтобы разделить вывод на отдельные подпроцессы.

Есть ли команда для объединения двух входных потоков?

Как бы я пошел по этому поводу? Как работает diff?

Кристиан Чиупиту
источник

Ответы:

105

Лично мой любимый (требует bash и других вещей, которые являются стандартными в большинстве дистрибутивов Linux)

Детали могут сильно зависеть от того, что выдают две вещи и как вы хотите объединить их ...

Содержимое command1 и command2 друг за другом в выводе:

cat <(command1) <(command2) > outputfile

Или, если обе команды выводят альтернативные версии одних и тех же данных, которые вы хотите видеть рядом (я использовал это с snmpwalk; числа с одной стороны и имена MIB с другой):

paste <(command1) <(command2) > outputfile

Или, если вы хотите сравнить выходные данные двух похожих команд (например, найти в двух разных каталогах)

diff <(command1) <(command2) > outputfile

Или, если они упорядочены какие-то результаты, объедините их:

sort -m <(command1) <(command2) > outputfile

Или запустите обе команды одновременно (хотя, возможно, немного перемешайте):

cat <(command1 & command2) > outputfile

Оператор <() устанавливает именованный канал (или / dev / fd) для каждой команды, направляя вывод этой команды в именованный канал (или ссылку на файл-указатель / dev / fd) и передает имя в командной строке. Есть эквивалент с> (). Вы можете сделать: command0 | tee >(command1) >(command2) >(command3) | command4одновременно отправить вывод одной команды, например, 4 другим командам.

Freiheit
источник
классно! я много раз читал справочную страницу bash, но не выбрал ее
Хавьер
2
Вы можете найти ссылку в [расширенном руководстве по написанию сценариев bash] ( tldp.org/LDP/abs/html/process-sub.html ) в проекте документации для linux
Брайс,
3
я был в состоянии предотвратить чередующиеся линии по конвейеру через grep --line-buffered- удобно для одновременно grep«т tailиз нескольких файлов журналов. см. stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO
16

Как catпоказывает горилла, вы можете добавить две пары к другой с помощью

Вы также можете создать FIFO, направить вывод команд на него, а затем прочитать из FIFO с помощью любой другой программы:

mkfifo ~/my_fifo
command1 > ~/my_fifo &
command2 > ~/my_fifo &
command3 < ~/my_fifo

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

Крис С
источник
2
Этот работает на pfSense (FreeBSD), а принятый ответ - нет. Спасибо!
Натан
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1и /tmp/p2ваши входные каналы, а /tmp/outputвыходной.

горилла
источник
6
Примечание. Если обе команды не ()сбрасывают свои выходные данные в каждой строке (и некоторые другие неясные правила POSIX для атомарности), вы можете
столкнуться
Разве вы не должны использовать точку с запятой вместо символа амперсанда?
Самир
это эпический материал
Mobigital
5

Для этого я создал специальную программу: fdlinecombine

Он читает несколько каналов (обычно программные выходы) и записывает их в стандартный вывод (вы также можете переопределить разделитель)

Vi.
источник
Работает как рекламируется. Спасибо, что сделали это публичным.
Алексей
3

Действительно классная команда, которую я использовал для этого tpipe, вам, возможно, придется скомпилировать, потому что она не такая распространенная. Он отлично подходит для того, чтобы делать именно то, о чем вы говорите, и он настолько чистый, что я обычно его устанавливаю. Справочная страница находится здесь http://linux.die.net/man/1/tpipe . Список загруженных файлов находится в этом архиве http://www.eurogaran.com/downloads/tpipe/ .

Это используется так,

## Reinject sub-pipeline stdout into standard output:
$ pipeline1 | tpipe "pipeline2" | pipeline3
Дж. М. Беккер
источник
3

Будьте осторожны здесь; простое их отслеживание приведет к тому, что результаты будут смешиваться так, как вы этого не хотите: например, если они представляют собой файлы журнала, вы, вероятно, не хотите, чтобы строка от одного вставлялась на полпути через строку от другого. Если это нормально, тогда

tail -f / tmp / p1 / tmp / p2> / tmp / output

будет работать. Если это не так , то вам нужно найти что-то, что будет выполнять буферизацию строк и выводить только полные строки. Системный журнал делает это, но я не уверен, что еще могло бы.

РЕДАКТИРОВАТЬ: оптимизация для небуферизованного чтения и именованных каналов:

рассматривая / tmp / p1, / ​​tmp / p2, / tmp / p3 как именованные каналы, созданные "mkfifo / tmp / p N "

tail -q -f / tmp / p1 / tmp / p2 | awk '{print $ 0> "/ tmp / p3"; закрыть ( "/ TMP / р3"); fflush ();} '&

теперь, таким образом, мы можем прочитать вывод именованного канала "/ tmp / p3" без буферизации :

tail -f / tmp / p3

Существует небольшая ошибка сортировки, вам нужно «инициализировать» 1-й канал ввода / tmp / p1:

echo -n> / tmp / p1

для того, чтобы tail примет вход от 2-го канала / tmp / p2 и не будет ждать, пока что-нибудь придет в / tmp / p1. это может быть не так, если вы уверены, что / tmp / p1 сначала получит ввод.

Также опция -q необходима для того, чтобы tail не печатал мусор с именами файлов.

pjz
источник
тем более полезным будет: "tail -q -f / tmp / p1 / tmp / p2 | another_command", так как это будет выполняться построчно, а с параметром -q он не будет печатать никакой другой мусор
readyblue
для небуферизованного файл / именем использования трубы: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & теперь / TMP / p3 может быть даже назван труба , и вы можете прочитать его, просто tail -f /tmp/p3все это UnBuffered = построчно есть однако небольшая ошибка из рода. 1-й файл / именованный канал должен быть инициализирован первым, чтобы tail принял выходные данные 2-го. так что вам нужно будет echo -n > /tmp/p1и чем все будет работать гладко.
ReadyBlue
1

Лучшая программа для этого lmerge. В отличие от ответа freihart, он ориентирован на строки, поэтому выходные данные двух команд не будут перекрывать друг друга. В отличие от других решений, он объединяет входные данные, поэтому ни одна команда не может доминировать в выходных данных. Например:

$ lmerge <(yes foo) <(yes bar) | head -n 4

Дает вывод:

foo
bar
foo
bar
Риан Хантер
источник