Объедините вывод двух параллельных программ с bash - PullRequest
15 голосов
/ 31 января 2012

Я хочу захватить вывод из двух параллельных программ (хвосты в лог-файлах) в один поток вывода в bash.

Я использовал этот пример программы для тестирования:

function foo { for i in $(seq 1 10); do echo "program $*"; sleep 1; done }

Теперь все работает нормально

(foo bar & foo baz &) | tee /tmp/output

но как только я добавляю дополнительную трубу в микс, она больше не работает:

(foo bar | grep bar & foo baz &) | tee /tmp/output # does't work

Выход становится последовательным. Я мог бы создать отдельную программу, включающую grep, но я хотел бы знать, есть ли способ обойти это.

Если кто-то может объяснить, почему это не работает, я был бы очень счастлив.

Ответы [ 2 ]

7 голосов
/ 31 января 2012

Отличный вопрос!Это меня немного озадачило, но я думаю, что знаю, что происходит.Происходит то, что grep буферизует вывод.Так что, если вы позволите ему бежать, вы увидите, что все это затопит в конце.Если вы используете GNU grep, попробуйте передать параметр --line-buffered:

(foo bar | grep --line-buffered bar & foo baz &) | tee /tmp/output

Чтобы рискнуть предположить, и учтите, что это по сути то, что это такое, я бы сказал, что grep буферизует больший вывод, потому что isatty(1) будет означать, что не записывает в TTY (даже если вы просматриваете вывод в TTY через tee).Буферизуя больше вывода, он делает меньше вызовов write() и более эффективен.Привычное поведение запуска grep и наблюдения за выводом в терминале - буферизация строк - строки появляются по мере их обнаружения.Эта опция заставляет grep работать в этом режиме.

Имейте в виду, что, как предупреждает man-страница, это может повлиять на производительность grep.

1 голос
/ 31 января 2012

Из-за использования канала между foo bar и grep вы выполняете команду grep для ожидания вывода команды foo bar, поэтому все строки с bar идут сразу после строк baz.Если вы действительно хотите извлечь что-то из команды, определите другую функцию, например:

function foo1 { for i in {1..3}; do echo "program $*" | grep "$*"; sleep 1; done }

и затем выполните:

(foo1 bar & foo baz &) | tee /tmp/output

Теперь вы заметите, что вывод выглядит так:

program baz
program bar
program baz
program bar
program baz
program bar
...
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...