पृष्ठभूमि प्रक्रिया का विश्वसनीय रिटर्न कोड


14

मान लें कि बैश कोड के निम्नलिखित टुकड़े हैं:

foo > logfile 2>&1 &
foo_pid=$!

while ps -p$foo_pid
do
    ping -c 1 localhost
done

wait $foo_pid

if [[ $? == 0 ]]
then
    echo "foo success"
fi

क्या यह मान लेना सुरक्षित है कि $?वास्तव में रिटर्न कोड शामिल है और रिटर्न कोड fooनहीं है ping? यदि उस प्रश्न का उत्तर है: "आप ऐसा नहीं मान सकते।" फिर मैं यह सुनिश्चित करने के लिए कोड के इस टुकड़े को कैसे संशोधित कर सकता हूं $?जिसमें हमेशा रिटर्न कोड होता है foo?

जवाबों:


12

साथ bash, आपको लगता है कि गारंटी होगा जब तक आप एक और पृष्ठभूमि काम शुरू कर दिया है (और सावधान रहना कि पृष्ठभूमि नौकरियों के साथ शुरू किया जा सकता &है लेकिन यह भी साथ coprocके बीच और इस प्रक्रिया प्रतिस्थापन के साथ) foo &और wait

POSIX के लिए आवश्यक है कि एक शेल जाने के बाद कम से कम 25 नौकरियों की निकास स्थिति कोbash याद रखे , लेकिन इससे बहुत अधिक याद रखता है।

अब, यदि आप करते हैं:

foo & pid=$!
...
bar &
wait "$pid"

आपको इस बात की कोई गारंटी नहीं है कि barउसे उसी तरह की पीडा नहीं दी जाएगी foo( जैसा fooकि समय barशुरू होने पर समाप्त हो गया है ), इसलिए भले ही इसकी संभावना न wait "$pid"हो , आपको बाहर निकलने की स्थिति दे सकती है bar

आप इसे पुन: प्रस्तुत कर सकते हैं:

bash -c '(exit 12; foo) & pid=$!
         while : bar & [ "$pid" != "$!" ]; do :;done
         wait "$pid"; echo "$?"'

जो (अंततः) आपको 0इसके बदले देगा 12

समस्या से बचने के लिए, इसे लिखने का एक तरीका होगा:

{
  foo_pid=$!

  while ps -p "$foo_pid"
  do
      ping -c 1 localhost
  done

  bar &
  ...

  read <&3 ret
  if [ "$ret" = 0 ]; then
    echo foo was sucessful.
  fi
} 3< <(foo > logfile 2>&1; echo "$?")

4

हां, आप wait "$!"बैकग्राउंड जॉब का दर्जा पाने के लिए भरोसा कर सकते हैं । स्क्रिप्ट के रूप में चलने पर, बैश स्वचालित रूप से पूर्ण पृष्ठभूमि की नौकरियों को इकट्ठा नहीं करता है। इस प्रकार यदि आप दौड़ते हैं wait, तो यह उस समय की नौकरी को इकट्ठा करेगा waitजिसे कहा जाता है।

आप एक साधारण स्क्रिप्ट के साथ इसका परीक्षण कर सकते हैं:

#!/bin/bash
sh -c 'sleep 1; exit 22' &
sleep 5
echo "FG: $?"
wait %1
echo "BG: $?"

जो आउटपुट देगा:

FG: 0
BG: 22

उस कथन का मुख्य भाग "स्क्रिप्ट के रूप में चलने पर" शुरुआत थी। जब इंटरैक्टिव, waitकाम नहीं करता है। प्रॉम्प्ट एकत्र किया जाता है और प्रॉम्प्ट (डिफ़ॉल्ट रूप से) प्रदर्शित होने से ठीक पहले बाहर निकलने की स्थिति को छोड़ दिया जाता है।
पैट्रिक

मैंने इसे बस 4.2.37, 4.1.2 और 3.2.48 पर बैश करने की कोशिश की। वे सभी ठीक उसी तरह का व्यवहार करते हैं (मेरे उत्तर में कोड की शाब्दिक प्रति / पेस्ट)। wait %1"ऐसी कोई काम" के रूप में पृष्ठभूमि प्रक्रिया "नींद 5" पूर्ण होने के बाद तुरंत एकत्र किया जाता है के साथ विफल रहता है।
पैट्रिक

आह ठीक है, क्षमा करें, मैं इसे अभी प्राप्त करता हूं। मैं आपकी %1जगह चूक गया था $!
स्टीफन चेजेलस

ध्यान दें कि bash -c '(sleep 1;exit 5) & sleep 2; wait %1; echo $?'(और साथ ही गैर-संवादात्मक) उस मृत नौकरी की निकास स्थिति प्राप्त करने में विफल रहता है। बग जैसा लगता है।
स्टीफन चेज़लस

जब तक मैंने इसे शामिल नहीं किया, यह मेकफिल नुस्खा के अंदर मेरे लिए काम नहीं करता था set +e। ऐसा लगता है कि बैश का set -eफंक्शन स्क्रिप्ट को मार देता है जैसे ही एक बुरा निकास कोड उठाया जाता हैwait
user5359531

0

मेरा मानना ​​है कि आपकी धारणा सही है। यहाँ man bashपृष्ठभूमि प्रक्रियाओं के लिए प्रतीक्षा के बारे में एक उद्धरण है।

यदि n किसी गैर-मौजूद प्रक्रिया या नौकरी को निर्दिष्ट करता है, तो रिटर्न की स्थिति 127 है। अन्यथा, वापसी की स्थिति अंतिम प्रक्रिया या नौकरी की प्रतीक्षा की स्थिति है।

तो शायद आपको 127 की जांच करनी चाहिए

मदद करने की तुलना में पूरी तरह से अलग जवाब के साथ एक समान सवाल है।

बैश स्क्रिप्ट प्रक्रियाओं के लिए प्रतीक्षा करें और रिटर्न कोड प्राप्त करें

संपादित करें 1

@ स्टीफन की टिप्पणियों और उत्तरों से प्रेरित होकर मैंने उनकी पटकथा का विस्तार किया है। लूज ट्रैक शुरू होने से पहले मैं लगभग 34 बैकग्राउंड प्रोसेस शुरू कर सकता हूं।

tback

$ cat tback 
plist=()
elist=()
slist=([1]=12 [2]=15 [3]=17 [4]=19 [5]=21 [6]=23)
count=30

#start background tasksto monitor
for i in 1 2 3 4
do
  #echo pid $i ${plist[$i]} ${slist[$i]}
  (echo $BASHPID-${slist[$i]} running; exit ${slist[$i]}) & 
  plist[$i]=$!
done

echo starting $count background echos to test history
for i in `eval echo {1..$count}`
do
  echo -n "." &
  elist[$i]=$! 
done
# wait for each background echo to complete
for i in `eval echo {1..$count}`
do
  wait ${elist[$i]}
  echo -n $? 
done
echo ""
# Now wait for each monitored process and check return status with expected
failed=0
for i in 1 2 3 4
do
  wait ${plist[$i]}
  rv=$?
  echo " pid ${plist[$i]} returns $rv should be ${slist[$i]}"
  if [[ $rv != ${slist[$i]} ]] 
  then
    failed=1
  fi
done

wait
echo "Complete $failed"
if [[ $failed = "1" ]]
then
  echo Failed
else
  echo Success
fi
exit $failed
$ 

मेरे सिस्टम पर उत्पादन होता है

$ bash tback
14553-12 running
14554-15 running
14555-17 running
starting 30 background echos to test history
14556-19 running
..............................000000000000000000000000000000
 pid 14553 returns 12 should be 12
 pid 14554 returns 15 should be 15
 pid 14555 returns 17 should be 17
 pid 14556 returns 19 should be 19
Complete 0
Success

1
नहीं, umlaute के जवाब के लिए मेरी टिप्पणी देखें , और इसे अपने लिए आज़माएंbash -c '(exit 12) & sleep 1; wait "$!"; echo "$?"'
स्टीफन चेज़लस

मैंने कभी भी bashढीली पटरी नहीं देखी है (हजारों काम शुरू करने के बाद भी), मेरा उदाहरण प्रदर्शन किया जा रहा है, जिसे पुन: उपयोग किया जा रहा है, जिसे आप अपने मामले में भी देख सकते हैं।
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.