Intereting Posts
Возможны ли жесткие ссылки для каталогов в файловых системах ext2 / 3/4? wget загрузить с помощью списка URL-адресов Добавьте 'Create launcher' в контекстное меню Nautilus (без `gnome-desktop-item-edit`) Невозможно добавить новый раздел с помощью fdisk – нет свободных секторов устаревшие пакетные перерывы yum для установки старшего JBoss Каковы предостережения по отправке электронной почты с помощью команды «mail»? Захват петли initrobfs busybox ext2 / 3/4 зарезервированные блоки процентное назначение Прогулки Многомерные массивы в Mawk `ln -s` создает символическую ссылку внутри существующей папки вместо отказа? Как использовать новые строки внутри () с sed? Возобновление прерванного процесса копирования Ошибка: неявное объявление функции 'rt_dev_socket' Ошибка yum: Ошибка: не удается получить метаданные репозитория (repomd.xml) для репозитория … Получить информацию о сети через терминал Ubuntu

Как «объединить» линии, напечатанные несколькими программами, безопасно?

Предположим, я хочу параллельно выполнять несколько программ и объединять их выходы в один канал:

sh -c ' (echo qqq; echo qqq2; echo qqq3)& (echo www; echo www2; echo www3)& (echo eee; echo eee2; echo eee3)& wait; wait; wait' 

Этот подход к оболочке хорошо работает для этого простого случая, но я ожидаю, что он потерпит неудачу, если программы выводят все больше и больше строк буферизованным способом, как это (построено):

 qqq qqwww q2 qqq3www2 wwweee3 eee2 eee3 

Одним из решений, которое я намекнул использовать, был tail -f :

 tail -n +0 -q -f <(echo qqq; echo qqq2; echo qqq3) <(echo www; echo www2; echo www3) <(echo eee; echo eee2; echo eee3) 

, но это неоптимальный вариант: он выводит данные вяло, он не заканчивается; Я вижу выходы не в порядке «сна», а в порядке аргументов в этом случае:

 tail -n +0 -q -f <(sleep 1; echo qqq; sleep 1; echo qqq2; echo qqq3) <(echo www; echo www2; sleep 10; echo www3) <(echo eee; sleep 4; echo eee2; echo eee3) | cat 

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

Как это сделать, используя стандартные инструменты (и без недостатка tail -f )?

Параллельно с GNU.

Из примечаний к выпуску от августа 2013 года:

--line-buffer будет буферизовать вывод на линии. --group держит вывод вместе для целой работы. --ungroup позволяет --ungroup с половиной строки, исходящей из одного задания, и половину строки, исходящей из другого задания. --line-buffer устанавливается между этими двумя; он печатает полную строку, но позволяет смешивать строки разных заданий.

Например:

parallel --line-buffer <jobs

Где находятся jobs :

 ./long.sh ./short.sh one ./short.sh two 

short.sh :

 #!/bin/bash while true; do echo "short line $1" sleep .1 done 

long.sh :

 #!/bin/bash count=0 while true; do echo -n "long line with multiple write()s " sleep .1 count=$((count+1)) if [ $count -gt 30 ]; then count=0 echo fi done 

Вывод:

 short line one short line two short line one short line two short line one **-snip-** short line one short line one short line two short line two short line one short line one short line one long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s long line with multiple write()s short line two short line two short line two short line one 

Решение, реализующее блокировки:

 function putlines () { read line || return $? while ! ln -s $$ lock >/dev/null 2>&1 do sleep 0.05 done echo "$line" } function getlines () { while read lline do echo "$lline" rm lock done } # your paralelized jobs ( job1 | putlines & job2 | putlines & job3 | putlines & wait ) | getlines| final_processing 

Должен быть более быстрый способ создания блокировки, чем использование файловой системы.

Я не могу придумать ничего простого, что поможет вам, если ваши строки будут такими длинными, что одна программа будет отправлена ​​спать до того, как она сможет, чтобы закончить запись строки в stdout.

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

Например:

 ((./script1 | while read line1; do echo $line1; done) & \ (./script2 | while read line2; do echo $line2; done)) | doSomethingWithOutput 

Вы можете сделать именованный канал с mkfifo , выгрузить весь вывод в именованный канал и отдельно прочитать из именованного канала для ваших собранных данных:

 mkfifo /tmp/mypipe job1 > /tmp/mypipe & job2 > /tmp/mypipe & job3 > /tmp/mypipe & cat /tmp/mypipe > /path/to/final_output & wait; wait; wait; wait