Terminem, który próbujesz osiągnąć, jest multipleksowanie .
Można to zrobić dość łatwo w bash, ale wymaga to bardziej zaawansowanych funkcji bash.
Stworzyłem skrypt oparty na twoim, który moim zdaniem robi to, co próbujesz osiągnąć. Wyjaśnię to poniżej.
#!/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
to funkcja bash, która po prostu odczytuje ze STDIN i zapisuje swój identyfikator i linię do STDOUT. Używamy $BASHPID
zamiast, $$
ponieważ $$
nie jest aktualizowany dla podpowłoki (co będziemy używać do uruchomienia manager
.
fds
to tablica, która będzie przechowywać deskryptory plików wskazujące na potoki STDIN różnych manager
s spawnowanych.
Następnie wykonujemy pętlę i tworzymy 5 procesów menedżera. Używam for (( ))
składni zamiast tego, jak to robiłeś, ponieważ jest czystsza. Jest to specyficzne dla bash, ale kilka rzeczy, które robi ten skrypt, jest specyficzne dla bash, więc równie dobrze może pójść na całość.
Następnie przechodzimy do exec {fd}> >(manager $i)
. Robi to jeszcze kilka rzeczy związanych z bash.
Pierwszy z nich to {fd}>
. Spowoduje to pobranie następnego dostępnego deskryptora pliku na numer 10 lub później, otwarcie potoku ze stroną zapisującą potoku przypisaną do tego deskryptora pliku i przypisanie numeru deskryptora pliku do zmiennej $fd
.
Do >(manager $i)
premiery manager $i
i zasadniczo substytuty >(manager $i)
o ścieżkę do standardowego wejścia tego procesu. Więc jeśli manager
został uruchomiony jako PID 1234, >(manager $i)
może zostać zastąpiony /proc/1234/fd/0
(to zależy od systemu operacyjnego).
Zakładając, że następnym dostępnym numerem deskryptora pliku jest 10, a menedżer jest uruchamiany z PID 1234, polecenie w exec {fd}> >(manager $i)
zasadzie staje się exec 10>/proc/1234/fd/0
, a bash ma teraz deskryptor pliku wskazujący STDIN tego menedżera.
Następnie, ponieważ bash wstawia numer tego deskryptora pliku $fd
, dodajemy ten deskryptor do tablicy w fds
celu późniejszego użycia.
Reszta jest dość prosta. Master odczytuje wiersz ze STDIN, iteruje wszystkie deskryptory plików $fds
i wysyła wiersz do tego desciptor pliku ( printf ... >&$fd
).
Wynik wygląda następująco:
$ /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
Gdzie wpisałem hello
i world
.