çoklu süreçler arasındaki iletişim


13

Ben x-times için ayrı bir işlem olarak manager () işlevini çalıştıran bir bash komut dosyası var. Komut dosyasındaki iletileri tüm manager () işlemlerine iletmek nasıl mümkün olur?

Ben anonim borular hakkında okudum ama onunla mesajları paylaşmak için nasıl bir fikrim yok .. Adlandırılmış borular ile yapmayı denedim, ama her işlem için ayrı bir adlandırılmış boru oluşturmak zorunda gibi görünüyor?

Bunu yapmanın en zarif yolu nedir?

İşte şimdiye kadar benim kod:

#!/bin/bash

manager () {
    while :
    do
        echo "read what has been passed to \$line"
    done
}

x=1
while [ $x -le 5 ]
do
  manager x &
  x=$(( $x + 1 ))
done


while :
do
while read line
do
  echo "What has been passed through the pipe is ${line}"
  # should pass $line to every manager process

done < $1
done

exit 0

Yanıtlar:


26

Yapmaya çalıştığınız şeyin terimi çoğullamadır .

Bu, bash'de oldukça kolay bir şekilde gerçekleştirilebilir, ancak daha gelişmiş bash özellikleri gerektirir.

Senin yapmaya çalıştığın şeyi yaptığını düşünüyorum senin dayalı bir senaryo oluşturdum. Aşağıda açıklayacağım.

#!/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

managerSTDIN'den basitçe okuyan ve tanımlayıcısını ve satırını STDOUT'a yazan bir bash işlevidir. Alt kabuklar için güncellenmemiş olarak kullanmak $BASHPIDyerine ( başlatmak için kullanacağımız şey budur .$$$$manager

fds, managerortaya çıkan çeşitli s'nin STDIN borularına işaret eden dosya tanımlayıcılarını tutacak bir dizidir .
Daha sonra 5 yönetici süreci oluşturup oluşturuyoruz. for (( ))Sözdizimini daha temiz olduğu gibi yapmak yerine kullanıyorum . Bu bash'a özgüdür, ancak bu betiğin yaptığı birkaç şey bash'a özgüdür, bu yüzden sonuna kadar gidebilir.
 

Sonra gidiyoruz exec {fd}> >(manager $i). Bu, bash'a özgü birkaç şey daha yapar.
Bunlardan ilki {fd}>. Bu, bir sonraki kullanılabilir dosya tanımlayıcısını 10 sayısı üzerinde veya sonrasında alır, borunun yazma tarafı o dosya tanımlayıcısına atanmış bir boru açar ve dosya tanımlayıcı numarasını değişkene atar $fd.

Bu işlemin bir STDIN yolunu >(manager $i)başlatır manager $ive temel olarak >(manager $i)onun yerine geçer . Bu nedenle manager, PID 1234 olarak başlatıldıysa, bunun >(manager $i)yerine ikame edilebilir /proc/1234/fd/0(bu işletim sistemine bağlıdır).

Dolayısıyla, bir sonraki kullanılabilir dosya tanımlayıcı numarasının 10 olduğunu ve PID 1234 ile yönetici başlatıldığını varsayarsak, komut exec {fd}> >(manager $i)temelde olur exec 10>/proc/1234/fd/0ve bash şimdi bu yöneticinin STDIN'ini gösteren dosya tanımlayıcıya sahiptir.
Sonra bash bu dosya tanımlayıcı numarasını koyduğundan, $fdbu tanımlayıcıyı fdsdaha sonra kullanmak üzere diziye ekleriz .
 

Geri kalanı oldukça basit. Master, STDIN'den bir satır okur, içindeki tüm dosya tanımlayıcılarını $fdstekrarlar ve satırı o dosya tanımlayıcısına ( printf ... >&$fd) gönderir .

 

Sonuç şuna benzer:

$ /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

Nereye yazdım hellove world.


@Patrick işe yarıyor, ancak bir yazım hatası var, {fd} ve $ {fd}
c4f4t0r olmalı

3
@ c4f4t0r Bu bir yazım hatası değil
Patrick

@Patrick on suse 11 "bash type.bash type.bash: line 10: exec: {fd}: bulunamadı" i $ {fd} olarak değişti ve şu şekilde çalışıyor
c4f4t0r

2
@ c4f4t0r Açık sigorta 11'deki bash sürümü oldukça eskidir (3.2). Bu özellik bash 4.0'da uygulanmıştır.
Patrick

Çok iyi bilgi için teşekkürler! Bir nitpick: Neden söyleyeceğinizi anlayabiliyorum echo -- "$line"ya da printf "%s\n" "$line"- ama bir --sonraki argüman sabit kodlanmışsa (ve başlamıyorsa -) neden kullanmanız gerekiyor ?
Scott

0

teeve bash:

cat foo | tee >(manager) >(manager) >(manager) >(manager) >(manager) >/dev/null

Yönetici sayısının yapılandırılabilir olması gerekiyorsa veya farklı yöneticilerin çıktılarının karıştırılmamasını istiyorsanız:

export -f manager
cat foo | parallel --pipe --tee manager ::: {1..10}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.