कई प्रक्रियाओं के बीच संचार


13

मेरे पास एक बैश स्क्रिप्ट है, जो एक्स-टाइम के लिए एक अलग प्रक्रिया के रूप में प्रबंधक () फ़ंक्शन चलाती है। स्क्रिप्ट के भीतर से सभी प्रबंधक () प्रक्रियाओं को संदेश अग्रेषित करना कैसे संभव है?

मैंने अनाम पाइपों के बारे में पढ़ा है, लेकिन मुझे पता नहीं है कि इसके साथ संदेशों को कैसे साझा किया जाए .. मैंने इसे नामित पाइपों के साथ करने की कोशिश की, लेकिन ऐसा लगता है कि मुझे प्रत्येक प्रक्रिया के लिए एक अलग नाम वाला पाइप बनाना होगा?

ऐसा करने का सबसे सुरुचिपूर्ण तरीका क्या है?

यहाँ मेरा कोड अब तक है:

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

जवाबों:


26

जो आप पूरा करने की कोशिश कर रहे हैं, उसके लिए शब्द बहुसंकेतन है

यह बैश में काफी आसानी से पूरा किया जा सकता है, लेकिन इसके लिए कुछ अधिक उन्नत बैश सुविधाओं की आवश्यकता होती है।

मैंने आपके आधार पर एक स्क्रिप्ट बनाई, जो मुझे लगता है कि वही करता है जो आप पूरा करने की कोशिश कर रहे हैं। मैं इसे नीचे समझाता हूँ।

#!/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एक बश फ़ंक्शन है जो बस STDIN से पढ़ता है और लिखता है कि यह पहचानकर्ता है और STDOUT को लाइन है। हम $BASHPIDइसके बजाय का उपयोग करते हैं $$जैसे $$उपधाराओं के लिए अद्यतन नहीं किया जाता है (जिसे हम लॉन्च करने के लिए उपयोग करेंगे manager

fdsएक ऐसा सरणी है जो फ़ाइल डिस्क्रिप्टर को विभिन्न managers स्पॉन्ड के STDIN पाइपों की ओर इंगित करता है।
फिर हम 5 प्रबंधक प्रक्रियाएँ बनाते और बनाते हैं। मैं for (( ))सिंटैक्स का उपयोग उस तरह से कर रहा हूं जैसे आप इसे क्लीनर के रूप में कर रहे थे। यह बैश स्पेसिफिक है, लेकिन इस स्क्रिप्ट की कई चीजें बैश स्पेसिफिक हैं, इसलिए हो सकता है कि सभी तरह से जाएं।
 

अगला हम करने के लिए मिलता है exec {fd}> >(manager $i)। यह कई और विशिष्ट चीजों को कोसता है।
जिसमें से पहला है {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



3
@ c4f4t0r यह टाइपो नहीं है
पैट्रिक

@Patrick suse 11 पर "bash type.bash type.bash: line 10: exec: {fd}: नहीं मिला" मैं $ {fd} को
निष्पादित

2
@ c4f4t0r खुले suse 11 में बैश का संस्करण बहुत प्राचीन (3.2) है। यह फीचर bash 4.0 में लागू किया गया था।
पैट्रिक

बहुत सारी अच्छी जानकारी के लिए धन्यवाद! एक निपिक: मैं समझ सकता हूं कि आप क्यों कहेंगे echo -- "$line"या printf "%s\n" "$line"- लेकिन --अगले तर्क के कठिन-कोडित होने पर आपको इसका उपयोग करने की आवश्यकता क्यों होगी (और इसके साथ शुरू नहीं होता है -)?
स्कॉट

0

teeऔर bash:

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

यदि प्रबंधकों की संख्या विन्यास योग्य होनी चाहिए या यदि आप चाहते हैं कि विभिन्न प्रबंधकों का आउटपुट मिश्रित न हो:

export -f manager
cat foo | parallel --pipe --tee manager ::: {1..10}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.