Термин для того, что вы пытаетесь достичь, означает мультиплексирование .
Это можно сделать довольно легко в bash, но для этого нужны некоторые более продвинутые функции bash.
Я создал сценарий на основе вашего, который, я думаю, делает то, что вы пытаетесь выполнить. Я объясню это ниже.
#!/bin/bash
manager() {
while IFS= read -r line; do
echo "manager[$1:$BASHPID]: $line"
done
}
fds=()
for (( i=0; i<5; i++ )); do
exec {fd}> >(manager $i)
fds+=( $fd )
done
while IFS= read -r line; do
echo "master: $line"
for fd in "${fds[@]}"; do
printf -- '%s\n' "$line" >&$fd
done
done
manager
это функция bash, которая просто читает из STDIN и записывает свой идентификатор и строку в STDOUT. Мы используем $BASHPID
вместо $$
as $$
не обновляется для подоболочек (это то, что мы будем использовать для запуска manager
.
fds
является массивом, который будет содержать файловые дескрипторы, указывающие на каналы STDIN различных manager
порожденных объектов .
Затем мы проходим цикл и создаем 5 процессов менеджера. Я использую for (( ))
синтаксис вместо того, как вы это делали, потому что он чище. Это зависит от bash, но некоторые вещи, которые выполняет этот скрипт, зависят от bash, поэтому вполне могут пройти весь путь.
Далее мы доберемся до exec {fd}> >(manager $i)
. Это делает еще несколько вещей, связанных с bash.
Первый из которых есть {fd}>
. Это захватывает следующий доступный дескриптор файла на или после числа 10, открывает канал с записывающей стороной канала, назначенной этому дескриптору файла, и назначает номер дескриптора файла переменной $fd
.
В >(manager $i)
запусках manager $i
и в основном заменители >(manager $i)
с путем к STDIN этого процесса. Так что, если он manager
был запущен как PID 1234, >(manager $i)
может быть заменен на /proc/1234/fd/0
(это зависит от ОС).
Таким образом, предполагая, что следующий доступный номер дескриптора файла равен 10, и менеджер запускается с PID 1234, команда в exec {fd}> >(manager $i)
основном становится exec 10>/proc/1234/fd/0
, и bash теперь имеет файловый дескриптор, указывающий на STDIN этого менеджера.
Затем, поскольку bash вставляет этот номер дескриптора файла $fd
, мы добавляем этот дескриптор в массив fds
для дальнейшего использования.
В остальном все довольно просто. Мастер читает строку из STDIN, перебирает все файловые дескрипторы $fds
и отправляет строку в этот дескриптор файла ( printf ... >&$fd
).
Результат выглядит так:
$ /tmp/test.sh
hello
master: hello
manager[0:8876]: hello
manager[1:8877]: hello
manager[4:8880]: hello
manager[2:8878]: hello
manager[3:8879]: hello
world
master: world
manager[0:8876]: world
manager[1:8877]: world
manager[3:8879]: world
manager[2:8878]: world
manager[4:8880]: world
Где я напечатал hello
и world
.
echo -- "$line"
илиprintf "%s\n" "$line"
- но зачем вам нужно использовать,--
когда следующий аргумент жестко задан (и не начинается с-
)?tee
иbash
:Если число менеджеров должно быть настраиваемым или если вы хотите, чтобы выходные данные разных менеджеров не смешивались:
источник