বহির্মুখী কোডটি কীভাবে শেষ করতে এবং প্রস্থান কোডটি ফেরত পেতে বাশ-এ অপেক্ষা করতে হবে! = 0 যখন কোনও উপ-প্রসেস কোড দিয়ে শেষ হয়! = 0?


561

এই স্ক্রিপ্টটি থেকে প্রস্থানিত কোডটি শেষ করতে এবং ফিরে আসতে বেশ কয়েকটি উপ-প্রক্রিয়াগুলির জন্য বাশ স্ক্রিপ্টে কীভাবে অপেক্ষা করবেন! = 0 যখন সাব-প্রসেসিসের কোনওটি কোড দিয়ে শেষ হয়! = 0?

সরল লিপি:

#!/bin/bash
for i in `seq 0 9`; do
  doCalculations $i &
done
wait

উপরের স্ক্রিপ্টটি সমস্ত 10 স্প্যানড সাব-প্রসেসের জন্য অপেক্ষা করবে, তবে এটি সর্বদা প্রস্থান স্থিতি 0 (দেখুন help wait) দেবে। আমি কীভাবে এই স্ক্রিপ্টটি সংশোধন করতে পারি যাতে এটি প্রসারিত সাবপ্রসেসিসগুলির প্রস্থান স্থিতিগুলি আবিষ্কার করতে পারে এবং প্রগতিগুলির কোনও কোড দিয়ে শেষ হলে প্রস্থান কোড 1 ফিরে আসবে! = 0?

উপ-প্রসেসগুলির পিআইডি সংগ্রহ করার চেয়ে এর জন্য আর কোনও ভাল সমাধান আছে কি না, যাতে তাদের জন্য ক্রম এবং অপেক্ষা করুন প্রস্থান স্থিতিগুলির জন্য?


1
এটি স্পর্শ করার জন্য উল্লেখযোগ্যভাবে উন্নত হতে পারে wait -n, কেবল প্রথম / পরবর্তী কমান্ডটি শেষ হলেই ফিরে আসার জন্য আধুনিক ব্যাশে উপলব্ধ।
চার্লস

আপনি যদি বাশ ব্যবহার করে পরীক্ষা করতে চান তবে এটি ব্যবহার করে দেখুন: github.com/sstephenson/bats
আলেকজান্ডার মিলস


3
@ চার্লসডুফির wait -nএকটি ছোট সমস্যা রয়েছে: যদি কোনও শিশু চাকরি না থাকে (ওরফে রেস শর্ত), এটি একটি শূন্য-বহির্গমন স্থিতি (ব্যর্থ) দেয় যা একটি ব্যর্থ শিশু প্রক্রিয়া থেকে পৃথক হতে পারে।
ড্রিভিকো

5
@ চার্লসডুফি - আপনার কাছে দুর্দান্ত অন্তর্দৃষ্টি রয়েছে এবং আপনি এটিকে ভাগ করে একটি বিশাল পরিষেবা করেন। দেখে মনে হচ্ছে যে আমি প্রায় 60% এসও পোস্ট পড়েছি সেগুলি আপনি অভিজ্ঞতার বিস্তৃত সমুদ্র থেকে আসা মন্তব্যে জ্ঞানের দুর্দান্ত সামান্য হীরা ভাগ করেছেন। অনেক ধন্যবাদ!
ব্রেট হলম্যান

উত্তর:


519

waitএছাড়াও (allyচ্ছিকভাবে) প্রক্রিয়াটির পিআইডি লাগে এবং takes সহ! আপনি পটভূমিতে চালু হওয়া শেষ কমান্ডের পিআইডি পাবেন। প্রতিটি তৈরি হওয়া সাব-প্রসেসির পিআইডি একটি অ্যারেতে সঞ্চয় করতে লুপটি সংশোধন করুন এবং তারপরে প্রতিটি পিআইডি-র জন্য অপেক্ষা করে লুপ করুন।

# run processes and store pids in array
for i in $n_procs; do
    ./procs[${i}] &
    pids[${i}]=$!
done

# wait for all pids
for pid in ${pids[*]}; do
    wait $pid
done

9
উইল, যেহেতু আপনি সমস্ত প্রক্রিয়াগুলির জন্য অপেক্ষা করতে যাচ্ছেন তা বিবেচ্য নয় যেমন উদাহরণস্বরূপ আপনি প্রথমটি অপেক্ষায় রয়েছেন যখন দ্বিতীয়টি ইতিমধ্যে শেষ হয়েছে (২ য়ভাবে পরবর্তী পুনরাবৃত্তিতে যেভাবেই নেওয়া হবে)। এটি একই পদ্ধতির যা আপনি সিতে অপেক্ষা সহ ব্যবহার করবেন (2)।
লুকা তেট্টেমন্তি

7
আহ, আমি দেখতে পাচ্ছি - বিভিন্ন ব্যাখ্যা :) আমি প্রশ্নটি " তত্ক্ষণাত উপস্থাপকগুলির কোনও প্রস্থান করলে অবিলম্বে প্রস্থান কোড 1 1" হিসাবে পড়ি ।
অ্যালনিটাক

56
পিআইডি প্রকৃতপক্ষে পুনরায় ব্যবহার করা যেতে পারে, তবে আপনি এমন প্রক্রিয়াটির জন্য অপেক্ষা করতে পারবেন না যা বর্তমান প্রক্রিয়াটির শিশু নয় (অপেক্ষা সেই ক্ষেত্রে ব্যর্থ হয়)।
tkokoszka

12
আপনি n: তম ব্যাকগ্রাউন্ড জব এবং %% সর্বাধিক সাম্প্রতিক কাজের জন্য উল্লেখ করতে% n ব্যবহার করতে পারেন।
join

30
@ নীল_এম: আপনি ঠিক বলেছেন, আমি দুঃখিত। সুতরাং এটি কিছু হবে: for i in $n_procs; do ./procs[${i}] & ; pids[${i}]=$!; done; for pid in ${pids[*]}; do wait $pid; done;ঠিক?
সিন্ডॅक

284

http://jeremy.zawodny.com/blog/archives/010717.html :

#!/bin/bash

FAIL=0

echo "starting"

./sleeper 2 0 &
./sleeper 2 1 &
./sleeper 3 0 &
./sleeper 2 0 &

for job in `jobs -p`
do
echo $job
    wait $job || let "FAIL+=1"
done

echo $FAIL

if [ "$FAIL" == "0" ];
then
echo "YAY!"
else
echo "FAIL! ($FAIL)"
fi

103
jobs -pকার্যকর করা অবস্থায় থাকা সাব-প্রসেসির পিআইডি দিচ্ছে s প্রক্রিয়া কল করার আগে শেষ হলে এটি একটি প্রক্রিয়া এড়িয়ে যাবে jobs -p। সুতরাং যদি কোনও সাবপ্রসেসের আগে শেষ হয় তবে jobs -pসেই প্রক্রিয়াটির প্রস্থান স্থিতি হারাবে ।
tkokoszka

15
বাহ, এই উত্তরটি শীর্ষ রেটযুক্তটির চেয়ে বেশ ভাল। : /
e40

4
@ e40 এবং নীচের উত্তর সম্ভবত আরও ভাল। এবং আরও ভাল হতে পারে প্রতিটি ('সেন্টিমিড; প্রতিধ্বনি "$?" >> "$ tmpfile") দিয়ে প্রতিটি কমান্ড চালানো, এই অপেক্ষাটি ব্যবহার করুন এবং তারপরে ব্যর্থতার জন্য ফাইলটি পড়ুন। এনেটেট-আউটপুটও। … বা আপনি যখন খুব বেশি যত্ন নেন না তখন এই স্ক্রিপ্টটি ব্যবহার করুন।
হোভারহেল

আমি যুক্ত করতে চাই যে এই উত্তরটি গৃহীত প্রশ্নের চেয়ে উত্তম
shurikk

2
@tkokoszka সঠিক হতে সাব-প্রোসেসিসের পিআইডিjobs -p দিচ্ছে না , বরং জিপিআইডি দিচ্ছে । অপেক্ষার যুক্তিটি যাইহোক কার্যকর হতে পারে বলে মনে হয়, এই গ্রুপটি উপস্থিত থাকলে এবং সর্বদা পিড না থাকলে এটি সর্বদা দলের জন্য অপেক্ষা করে তবে সচেতন হওয়া ভাল .. বিশেষত যদি কেউ এটি তৈরি করে সাব-প্রসেসে বার্তা প্রেরণের মতো কিছু অন্তর্ভুক্ত করে থাকে কেস সিনট্যাক্স আপনি PIDs বা GPIDs .. অর্থাত আছে কিনা তার উপর নির্ভর করে ভিন্ন বনামkill -- -$GPIDkill $PID
টিমো

58

এখানে ব্যবহার করে সাধারণ উদাহরণ wait

কিছু প্রক্রিয়া চালান:

$ sleep 10 &
$ sleep 10 &
$ sleep 20 &
$ sleep 20 &

অতঃপর তাদেরকে waitআদেশ দিয়ে অপেক্ষা করুন :

$ wait < <(jobs -p)

বা শুধু wait(যুক্তি ছাড়াই) সবার জন্য।

ব্যাকগ্রাউন্ডে সমস্ত কাজ শেষ হওয়ার জন্য এটি অপেক্ষা করবে।

তাহলে -nবিকল্প সরবরাহ করা হয়, পরবর্তী কাজের জন্য অপেক্ষা করছে বিনষ্ট এবং তার প্রস্থানের অবস্থা ফেরৎ করতে।

দেখুন: help waitএবং help jobsবাক্য গঠন জন্য।

তবে খারাপ দিকটি হ'ল এটি কেবল সর্বশেষ আইডির স্থিতিতে ফিরে আসবে, সুতরাং আপনাকে প্রতিটি উপ-প্রসেসের জন্য স্থিতিটি পরীক্ষা করতে হবে এবং এটি ভেরিয়েবলের মধ্যে সঞ্চয় করতে হবে।

অথবা ব্যর্থতায় কিছু ফাইল তৈরি করতে আপনার গণনা ফাংশনটি তৈরি করুন (খালি বা ব্যর্থ লগ সহ), তারপরে যদি উপস্থিত থাকে তবে সেই ফাইলটি পরীক্ষা করুন, যেমন

$ sleep 20 && true || tee fail &
$ sleep 20 && false || tee fail &
$ wait < <(jobs -p)
$ test -f fail && echo Calculation failed.

1
নতুনদের বশ করার জন্য, এখানে উদাহরণের দুটি গণনা এখানে sleep 20 && trueএবং sleep 20 && false- যেমন: আপনার ফাংশন (গুলি) দিয়ে তাদের প্রতিস্থাপন করুন। বুঝতে &&এবং ||চালাতে man bashএবং '/' (অনুসন্ধান) টাইপ করুন এবং তারপরে '^ * তালিকাগুলি' (একটি রেজেক্স) লিখুন তারপরে প্রবেশ করুন: মানুষ বর্ণনায় নীচে স্ক্রোল করবে &&এবং||
ড্রায়ভিকো

1
আপনার সম্ভবত পরীক্ষা করা উচিত যে ফাইলটি 'ব্যর্থ' শুরুতে নেই (বা এটি মুছুন)। অ্যাপ্লিকেশনটির উপর নির্ভর করে, ||এসটিডিআরআরটিকে ব্যর্থ হওয়ার আগে ধরা পড়ার আগে '2> & 1' যুক্ত করা ভাল ধারণাও হতে পারে ।
ড্রিভিকো

আমি এই এক পছন্দ, কোন ত্রুটি? আসলে, আমি কেবল তখন সমস্ত উপ-প্রসেসের তালিকা তৈরি করতে এবং কিছু পদক্ষেপ নিতে চাই, যেমন eg সিগন্যাল প্রেরণ করুন, আমি বুককিপিং পিডগুলি বা পুনরাবৃত্ত চাকরির চেষ্টা করব। wait
সমাপ্তির

এটি চাকরির বহির্গমন স্থিতি মিস করবে যা জব-
পি

50

আপনার যদি জিএনইউ সমান্তরাল ইনস্টল থাকে তবে আপনি এটি করতে পারেন:

# If doCalculations is a function
export -f doCalculations
seq 0 9 | parallel doCalculations {}

জিএনইউ সমান্তরাল আপনাকে প্রস্থান কোড দেবে:

  • 0 - সমস্ত কাজ ত্রুটি ছাড়াই চলেছে।

  • 1-253 - কিছু কাজ ব্যর্থ হয়েছে। প্রস্থান স্থিতি ব্যর্থ কাজের সংখ্যা দেয়

  • 254 - 253 টিরও বেশি কাজ ব্যর্থ হয়েছে।

  • 255 - অন্যান্য ত্রুটি।

আরও জানতে ইন্ট্রো ভিডিও দেখুন: http://pi.dk/1


1
ধন্যবাদ! কিন্তু আপনি "বিভ্রান্তির" ইস্যু যা আমি পরবর্তীতে খোলস মধ্যে উল্লেখ করতে ভুলে গেছি unix.stackexchange.com/a/35953
nobar

1
এটি দুর্দান্ত সরঞ্জামের মতো দেখায়, তবে আমি মনে করি না যে উপরেরটি কোনও বাশ স্ক্রিপ্টে যেমন রয়েছে তেমন কাজ করে যেখানে doCalculationsএকই স্ক্রিপ্টে কোনও ফাংশন সংজ্ঞায়িত করা হয় (যদিও ওপি এই প্রয়োজনীয়তা সম্পর্কে পরিষ্কার ছিল না)। আমি যখন চেষ্টা করি, তখন parallelবলে /bin/bash: doCalculations: command not found(এটি seq 0 9উপরের উদাহরণের জন্য এটি 10 ​​বার বলে )। একটি কর্মক্ষেত্র জন্য এখানে দেখুন ।
নোটার

3
আগ্রহের এছাড়াও: বিকল্পের xargsমাধ্যমে সমান্তরালভাবে কাজ শুরু করার কিছুটা ক্ষমতা রয়েছে -P। থেকে এখানে : export -f doCalculations ; seq 0 9 |xargs -P 0 -n 1 -I{} bash -c "doCalculations {}"। এর সীমাবদ্ধতাগুলি xargsম্যান পৃষ্ঠাতে গণিত করা হয় parallel
নোটার

এবং যদি doCalculationsঅন্য কোনও স্ক্রিপ্ট-অভ্যন্তরীণ পরিবেশের ভেরিয়েবলগুলি (কাস্টম PATHইত্যাদি) উপর নির্ভর করে তবে তাদের সম্ভবত exportপ্রবর্তনের আগে স্পষ্টভাবে সম্পাদনা করা দরকার parallel
নবার

4
@ নোবার এই বিভ্রান্তির কারণ হ'ল কিছু প্যাকেজকারী তাদের ব্যবহারকারীদের জন্য গোলমাল করছে। আপনি যদি ব্যবহার করে ইনস্টল করেন তবে wget -O - pi.dk/3 | shকোনও বিভ্রান্তি পাবেন না। যদি আপনার প্যাকেজকারী আপনার জন্য জিনিসগুলি গোলমেলে ফেলেছে তবে আমি আপনাকে আপনার প্যাকেজরের সাথে বিষয়টি উত্থাপন করতে উত্সাহিত করব। GNU সমান্তরালে তাদের দেখতে ভেরিয়েবল এবং ফাংশন এক্সপোর্ট (এক্সপোর্ট -f) করা উচিত (দেখুন man parallel: gnu.org/software/parallel/… )
ওলে

46

কীভাবে সহজভাবে:

#!/bin/bash

pids=""

for i in `seq 0 9`; do
   doCalculations $i &
   pids="$pids $!"
done

wait $pids

...code continued here ...

হালনাগাদ:

একাধিক মন্তব্যকারী দ্বারা চিহ্নিত হিসাবে, উপরেরগুলি সমস্ত প্রক্রিয়া চালিয়ে যাওয়ার আগে শেষ হওয়ার জন্য অপেক্ষা করে, তবে প্রস্থান করে এবং ব্যর্থ হয় না যদি তাদের মধ্যে একটি ব্যর্থ হয় তবে এটি @ ব্রায়ান, @ স্যামব্রাইটম্যান এবং অন্যদের দ্বারা প্রস্তাবিত নিম্নলিখিত পরিবর্তনটি করা যেতে পারে :

#!/bin/bash

pids=""
RESULT=0


for i in `seq 0 9`; do
   doCalculations $i &
   pids="$pids $!"
done

for pid in $pids; do
    wait $pid || let "RESULT=1"
done

if [ "$RESULT" == "1" ];
    then
       exit 1
fi

...code continued here ...

1
ওয়েট ম্যান পৃষ্ঠাগুলি অনুসারে, একাধিক পিআইডি'র একমাত্র প্রত্যাশিত শেষ প্রক্রিয়ার রিটার্ন মানটির জন্য অপেক্ষা করুন। সুতরাং আপনাকে অতিরিক্ত লুপের প্রয়োজন হবে এবং স্বীকৃত উত্তরে (মন্তব্যে) পরামর্শ অনুসারে প্রতিটি পিআইডি আলাদাভাবে অপেক্ষা করুন।
ভ্লাদ ফ্রোলভ

1
কারণ এই পৃষ্ঠায় অন্য কোথাও বলা হয়েছে বলে মনে হচ্ছে না, আমি যুক্ত করব লুপটি হবেfor pid in $pids; do wait $pid; done
ব্রায়ান

1
@ বিজনাউন্টস_ট্রকনকনস হ্যাঁ, আপনি করেন। দেখুন help wait- একাধিক আইডি সহ waitকেবলমাত্র শেষের প্রস্থান কোডটি ফেরত দেয়, যেমন উপরে উপরে বলেছেন @ ভ্লাদ-ফ্রলোভ।
স্যাম ব্রাইটম্যান

1
ব্রায়ান, @ স্যামব্রেটম্যান ঠিক আছে। আমি আপনার recomendations সঙ্গে এটি পরিবর্তন।
patapouf_ai

4
এই সমাধানটির সাথে আমার স্পষ্ট উদ্বেগ ছিল: যদি কোনও প্রদত্ত প্রক্রিয়াটি সংশ্লিষ্ট বলার আগেই প্রস্থান করে তবে waitকী হবে? দেখা যাচ্ছে যে এটি কোনও সমস্যা নয়: আপনি যদি waitইতিমধ্যে বের হয়ে আসা কোনও প্রক্রিয়াটিতে থাকেন waitতবে অবিলম্বে ইতিমধ্যে উপস্থিত-হওয়া প্রক্রিয়াটির স্থিতিটি থেকে বেরিয়ে আসবে। (আপনাকে ধন্যবাদ, bashলেখক!)
ড্যানিয়েল গ্রিসকম

39

আমি এতদূর যা নিয়ে এসেছি তা এখানে। আমি দেখতে চাই যে কীভাবে কোনও শিশু অবসান হলে স্লিপ কমান্ডটি বাধাগ্রস্থ করতে পারে, যাতে কারও WAITALL_DELAYনিজের ব্যবহারের সাথে সুর করতে না হয় ।

waitall() { # PID...
  ## Wait for children to exit and indicate whether all exited with 0 status.
  local errors=0
  while :; do
    debug "Processes remaining: $*"
    for pid in "$@"; do
      shift
      if kill -0 "$pid" 2>/dev/null; then
        debug "$pid is still alive."
        set -- "$@" "$pid"
      elif wait "$pid"; then
        debug "$pid exited with zero exit status."
      else
        debug "$pid exited with non-zero exit status."
        ((++errors))
      fi
    done
    (("$#" > 0)) || break
    # TODO: how to interrupt this sleep when a child terminates?
    sleep ${WAITALL_DELAY:-1}
   done
  ((errors == 0))
}

debug() { echo "DEBUG: $*" >&2; }

pids=""
for t in 3 5 4; do 
  sleep "$t" &
  pids="$pids $!"
done
waitall $pids

কেউ সম্ভবত WAITALL_DELAY এড়িয়ে যেতে বা এটি খুব কম সেট করতে পারে, কারণ লুপের অভ্যন্তরে কোনও প্রক্রিয়া শুরু হয় না বলে আমি মনে করি এটি খুব ব্যয়বহুল নয়।
মারিয়ান

21

এটি সমান্তরাল করতে ...

for i in $(whatever_list) ; do
   do_something $i
done

এটি এ অনুবাদ করুন ...

for i in $(whatever_list) ; do echo $i ; done | ## execute in parallel...
   (
   export -f do_something ## export functions (if needed)
   export PATH ## export any variables that are required
   xargs -I{} --max-procs 0 bash -c ' ## process in batches...
      {
      echo "processing {}" ## optional
      do_something {}
      }' 
   )
  • যদি কোনও প্রক্রিয়াতে ত্রুটি দেখা দেয়, তবে এটি অন্যান্য প্রক্রিয়াগুলিকে বাধাগ্রস্ত করবে না, তবে এটি ক্রমটি সম্পূর্ণরূপে একটি শূন্য-বহির্গমন কোডের ফলাফল করবে
  • ফাংশন এবং ভেরিয়েবল রফতানি করা বিশেষ কোনও ক্ষেত্রে প্রয়োজনীয় বা নাও হতে পারে।
  • আপনি --max-procsকতটা সমান্তরালতা চান তার উপর ভিত্তি করে সেট করতে পারেন (0 যার অর্থ "একবারে একবারে")।
  • GNU সমান্তরাল এর জায়গায় ব্যবহার করার সময় কিছু অতিরিক্ত বৈশিষ্ট্য সরবরাহ করেxargs - তবে এটি সর্বদা ডিফল্টরূপে ইনস্টল হয় না।
  • forলুপ যেহেতু এই উদাহরণে কঠোরভাবে প্রয়োজন নেই echo $iমূলত শুধু আউটপুট ঘটার সম্ভবনা নেই $(whatever_list)। আমি শুধু এর ব্যবহার মনে করিfor কীওয়ার্ডটির কী চলছে তা দেখতে কিছুটা সহজ করে তোলে।
  • বাশ স্ট্রিং হ্যান্ডলিং বিভ্রান্ত হতে পারে - আমি খুঁজে পেয়েছি যে সিঙ্গল কোটগুলি ব্যবহার করা অ-তুচ্ছ স্ক্রিপ্টগুলি মোড়ানোর জন্য সবচেয়ে ভাল কাজ করে।
  • আপনি সহজেই পুরো ক্রিয়াকে বাধা দিতে পারেন (^ C বা অনুরূপ ব্যবহার করে), বাশ সমান্তরালতার আরও সরাসরি পদ্ধতির বিপরীতে

এখানে একটি সরলীকৃত কাজের উদাহরণ ...

for i in {0..5} ; do echo $i ; done |xargs -I{} --max-procs 2 bash -c '
   {
   echo sleep {}
   sleep 2s
   }'


7

আমি বিশ্বাস করি না বাশের বিল্টিন কার্যকারিতা দিয়ে এটি সম্ভব with

কোনও শিশু বাইরে বের হলে আপনি বিজ্ঞপ্তিটি পেতে পারেন :

#!/bin/sh
set -o monitor        # enable script job control
trap 'echo "child died"' CHLD

তবে সিগন্যাল হ্যান্ডলারে সন্তানের প্রস্থান স্থিতির কোনও আপাত উপায় নেই।

সেই সন্তানের মর্যাদা পাওয়া সাধারণত waitনিম্ন স্তরের POSIX API এ ফাংশনগুলির পরিবারের কাজ of দুর্ভাগ্যক্রমে এর জন্য বাশের সমর্থন সীমিত - আপনি একটি নির্দিষ্ট শিশু প্রক্রিয়াটির জন্য অপেক্ষা করতে পারেন (এবং এটির প্রস্থান স্থিতি পেতে পারেন) বা আপনি তাদের সবার জন্য অপেক্ষা করতে পারেন এবং সর্বদা 0 ফলাফল পান।

যা করা অসম্ভব বলে মনে হচ্ছে এটি তার সমতুল্য waitpid(-1), যে কোনও শিশু প্রক্রিয়া ফিরে না আসা পর্যন্ত অবরুদ্ধ করে।


7

আমি এখানে তালিকাভুক্ত প্রচুর ভাল উদাহরণ দেখতে পাচ্ছি, আমারও ভালভাবে ফেলে দিতে চেয়েছি।

#! /bin/bash

items="1 2 3 4 5 6"
pids=""

for item in $items; do
    sleep $item &
    pids+="$! "
done

for pid in $pids; do
    wait $pid
    if [ $? -eq 0 ]; then
        echo "SUCCESS - Job $pid exited with a status of $?"
    else
        echo "FAILED - Job $pid exited with a status of $?"
    fi
done

আমি সমান্তরালভাবে সার্ভার / পরিষেবাদি শুরু / বন্ধ করার জন্য খুব অনুরূপ কিছু ব্যবহার করি এবং প্রতিটি প্রস্থান স্থিতি পরীক্ষা করি। আমার জন্য দুর্দান্ত কাজ করে এই কেউ সাহায্য করে আউট আশা করি!


আমি যখন এটি সিটিআরএল + সিআই দিয়ে থামিয়ে দিই তবুও পটভূমিতে প্রক্রিয়াগুলি চলতে দেখি।
কার্স্টেন

2
@ কারস্টেন - এটি একটি ভিন্ন সমস্যা। ধরে নিই যে আপনি ব্যাশ ব্যবহার করছেন আপনি একটি প্রস্থান শর্তটি আটকে ফেলতে পারেন (সিটিআরএল + সি সহ) এবং বর্তমান এবং সমস্ত শিশু প্রক্রিয়া ব্যবহার করে হত্যা করতে পারবেনtrap "kill 0" EXIT
ফিল

@ ফিল ঠিক আছে। যেহেতু এগুলি ব্যাকগ্রাউন্ড প্রক্রিয়া, তাই পিতামাতার প্রক্রিয়াটি হত্যার ফলে যে কোনও শিশু প্রক্রিয়া চলমান থাকে। আমার উদাহরণ কোনও সংকেতকে ফাঁদে ফেলে না, যা ফিল হিসাবে বলেছে প্রয়োজন অনুসারে যোগ করা যেতে পারে।
জেসন স্লোবটস্কি

6

এটি এমন কিছু যা আমি ব্যবহার করি:

#wait for jobs
for job in `jobs -p`; do wait ${job}; done

5

নীচের কোডটি সমস্ত গণনা সম্পন্ন হওয়ার অপেক্ষায় থাকবে এবং যদি কোনও ডক্যালকুলেশন ব্যর্থ হয় তবে প্রস্থান প্রস্থান 1 টির জন্য অপেক্ষা করবে ।

#!/bin/bash
for i in $(seq 0 9); do
   (doCalculations $i >&2 & wait %1; echo $?) &
done | grep -qv 0 && exit 1

5

শেল থেকে ফলাফলগুলি কেবল স্টোর করুন, যেমন একটি ফাইলের মধ্যে।

#!/bin/bash
tmp=/tmp/results

: > $tmp  #clean the file

for i in `seq 0 9`; do
  (doCalculations $i; echo $i:$?>>$tmp)&
done      #iterate

wait      #wait until all ready

sort $tmp | grep -v ':0'  #... handle as required

5

এখানে আমার সংস্করণ যা একাধিক পিডের জন্য কাজ করে, কার্যকর যদি খুব বেশি সময় লাগে তবে সতর্কতা লগ করে এবং যদি নির্ধারিত মানের চেয়ে বেশি সময় নেয় তবে সাব-প্রসেসগুলি বন্ধ করে দেয়।

function WaitForTaskCompletion {
    local pids="${1}" # pids to wait for, separated by semi-colon
    local soft_max_time="${2}" # If execution takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0.
    local hard_max_time="${3}" # If execution takes longer than $hard_max_time seconds, will stop execution, unless $hard_max_time equals 0.
    local caller_name="${4}" # Who called this function
    local exit_on_error="${5:-false}" # Should the function exit program on subprocess errors       

    Logger "${FUNCNAME[0]} called by [$caller_name]."

    local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once 
    local log_ttime=0 # local time instance for comparaison

    local seconds_begin=$SECONDS # Seconds since the beginning of the script
    local exec_time=0 # Seconds since the beginning of this function

    local retval=0 # return value of monitored pid process
    local errorcount=0 # Number of pids that finished with errors

    local pidCount # number of given pids

    IFS=';' read -a pidsArray <<< "$pids"
    pidCount=${#pidsArray[@]}

    while [ ${#pidsArray[@]} -gt 0 ]; do
        newPidsArray=()
        for pid in "${pidsArray[@]}"; do
            if kill -0 $pid > /dev/null 2>&1; then
                newPidsArray+=($pid)
            else
                wait $pid
                result=$?
                if [ $result -ne 0 ]; then
                    errorcount=$((errorcount+1))
                    Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]."
                fi
            fi
        done

        ## Log a standby message every hour
        exec_time=$(($SECONDS - $seconds_begin))
        if [ $((($exec_time + 1) % 3600)) -eq 0 ]; then
            if [ $log_ttime -ne $exec_time ]; then
                log_ttime=$exec_time
                Logger "Current tasks still running with pids [${pidsArray[@]}]."
            fi
        fi

        if [ $exec_time -gt $soft_max_time ]; then
            if [ $soft_alert -eq 0 ] && [ $soft_max_time -ne 0 ]; then
                Logger "Max soft execution time exceeded for task [$caller_name] with pids [${pidsArray[@]}]."
                soft_alert=1
                SendAlert

            fi
            if [ $exec_time -gt $hard_max_time ] && [ $hard_max_time -ne 0 ]; then
                Logger "Max hard execution time exceeded for task [$caller_name] with pids [${pidsArray[@]}]. Stopping task execution."
                kill -SIGTERM $pid
                if [ $? == 0 ]; then
                    Logger "Task stopped successfully"
                else
                    errrorcount=$((errorcount+1))
                fi
            fi
        fi

        pidsArray=("${newPidsArray[@]}")
        sleep 1
    done

    Logger "${FUNCNAME[0]} ended for [$caller_name] using [$pidCount] subprocesses with [$errorcount] errors."
    if [ $exit_on_error == true ] && [ $errorcount -gt 0 ]; then
        Logger "Stopping execution."
        exit 1337
    else
        return $errorcount
    fi
}

# Just a plain stupid logging function to replace with yours
function Logger {
    local value="${1}"

    echo $value
}

উদাহরণস্বরূপ, তিনটি প্রক্রিয়া শেষ হওয়ার জন্য অপেক্ষা করুন, কার্যকরকরণটি যদি 5 সেকেন্ডের চেয়ে বেশি সময় নেয় তবে একটি সতর্কতা লগ করুন, এক্সিকিউশনটি যদি 120 সেকেন্ডের বেশি সময় নেয় তবে সমস্ত প্রক্রিয়া বন্ধ করুন। ব্যর্থতায় প্রোগ্রাম থেকে প্রস্থান করবেন না।

function something {

    sleep 10 &
    pids="$!"
    sleep 12 &
    pids="$pids;$!"
    sleep 9 &
    pids="$pids;$!"

    WaitForTaskCompletion $pids 5 120 ${FUNCNAME[0]} false
}
# Launch the function
someting

4

আপনার কাছে যদি 4.4 বাশ বা পরে পাওয়া যায় তবে নিম্নলিখিতগুলি আপনার পক্ষে কার্যকর হতে পারে। এটি টাস্কের নাম এবং তাদের "কোড" পাশাপাশি টাস্কের নাম এবং তাদের পিডস সংরক্ষণ করতে সংযুক্ত অ্যারে ব্যবহার করে। আমি একটি সাধারণ রেট-সীমাবদ্ধ পদ্ধতিও তৈরি করেছি যা কার্যকর হতে পারে যদি আপনার কাজগুলি সিপিইউ বা I / O সময় প্রচুর পরিমাণে গ্রাস করে এবং আপনি যদি সামনের কাজগুলি সীমাবদ্ধ করতে চান।

স্ক্রিপ্টটি প্রথম লুপে সমস্ত কাজ শুরু করে এবং দ্বিতীয়টির ফলাফলগুলি গ্রাস করে।

এটি সাধারণ ক্ষেত্রে কিছুটা ওভারকিল তবে এটি বেশ ঝরঝরে স্টাফের জন্য অনুমতি দেয়। উদাহরণস্বরূপ, কেউ প্রতিটি কাজের জন্য ত্রুটি বার্তাগুলি অন্য মিশ্র অ্যারেতে সঞ্চয় করতে পারে এবং সবকিছু স্থির হয়ে যাওয়ার পরে সেগুলি মুদ্রণ করতে পারে।

#! /bin/bash

main () {
    local -A pids=()
    local -A tasks=([task1]="echo 1"
                    [task2]="echo 2"
                    [task3]="echo 3"
                    [task4]="false"
                    [task5]="echo 5"
                    [task6]="false")
    local max_concurrent_tasks=2

    for key in "${!tasks[@]}"; do
        while [ $(jobs 2>&1 | grep -c Running) -ge "$max_concurrent_tasks" ]; do
            sleep 1 # gnu sleep allows floating point here...
        done
        ${tasks[$key]} &
        pids+=(["$key"]="$!")
    done

    errors=0
    for key in "${!tasks[@]}"; do
        pid=${pids[$key]}
        local cur_ret=0
        if [ -z "$pid" ]; then
            echo "No Job ID known for the $key process" # should never happen
            cur_ret=1
        else
            wait $pid
            cur_ret=$?
        fi
        if [ "$cur_ret" -ne 0 ]; then
            errors=$(($errors + 1))
            echo "$key (${tasks[$key]}) failed."
        fi
    done

    return $errors
}

main

4

আমি সবে স্ক্রিপ্টটি ব্যাকগ্রাউন্ডে পরিবর্তন করেছি এবং একটি প্রক্রিয়াটিকে সমান্তরাল করে তুলছি।

আমি কিছু পরীক্ষা-নিরীক্ষা করেছি (বাশ ও কেএসএস উভয় দিয়ে সোলারিসে) এবং আবিষ্কার করেছি যে 'অপেক্ষা' প্রস্থান স্থিতি শূন্য না হলে, বা কোনও পিআইডি যুক্তি সরবরাহ না করা হলে শূন্য-বহির্গমন প্রস্থান করে এমন চাকরির তালিকা তৈরি করে। যেমন

ব্যাশ:

$ sleep 20 && exit 1 &
$ sleep 10 && exit 2 &
$ wait
[1]-  Exit 2                  sleep 20 && exit 2
[2]+  Exit 1                  sleep 10 && exit 1

ksh:

$ sleep 20 && exit 1 &
$ sleep 10 && exit 2 &
$ wait
[1]+  Done(2)                  sleep 20 && exit 2
[2]+  Done(1)                  sleep 10 && exit 1

এই আউটপুটটি স্ট্যাডারকে লেখা হয়েছে, সুতরাং অপের উদাহরণের একটি সহজ সমাধান হতে পারে:

#!/bin/bash

trap "rm -f /tmp/x.$$" EXIT

for i in `seq 0 9`; do
  doCalculations $i &
done

wait 2> /tmp/x.$$
if [ `wc -l /tmp/x.$$` -gt 0 ] ; then
  exit 1
fi

যদিও এটি:

wait 2> >(wc -l)

tmp ফাইল ছাড়াই একটি গণনাও ফেরত দেবে। এটি এইভাবে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ:

wait 2> >(if [ `wc -l` -gt 0 ] ; then echo "ERROR"; fi)

এটি টিএমপি ফাইল আইএমওর চেয়ে খুব বেশি কার্যকর নয়। আমি টিএমপি ফাইলটি এড়ানোর কোনও কার্যকর উপায় খুঁজে পাইনি যদিও সাবস্কেলে "অপেক্ষা করুন" চালানো এড়ানো হবে, যা কিছুতেই কাজ করবে না।


3

আমি এখানে গিয়েছিলাম এবং এখানে অন্যান্য উদাহরণ থেকে সমস্ত ভাল অংশ একত্রিত। এই স্ক্রিপ্টটি checkpidsযখন কোনও ব্যাকগ্রাউন্ড প্রক্রিয়াটি প্রস্থান করে এবং ভোটদানের অবলম্বন না করে প্রস্থান স্থিতি আউটপুট কার্যকর করে will

#!/bin/bash

set -o monitor

sleep 2 &
sleep 4 && exit 1 &
sleep 6 &

pids=`jobs -p`

checkpids() {
    for pid in $pids; do
        if kill -0 $pid 2>/dev/null; then
            echo $pid is still alive.
        elif wait $pid; then
            echo $pid exited with zero exit status.
        else
            echo $pid exited with non-zero exit status.
        fi
    done
    echo
}

trap checkpids CHLD

wait

3
#!/bin/bash
set -m
for i in `seq 0 9`; do
  doCalculations $i &
done
while fg; do true; done
  • set -m আপনাকে স্ক্রিপ্টে fg & bg ব্যবহার করতে দেয়
  • fgঅগ্রভাগে সর্বশেষ প্রক্রিয়াটি সংযোজন করা ছাড়াও, প্রক্রিয়াটি পূর্বরূপ হিসাবে প্রস্থান হিসাবে একই প্রস্থান স্থিতি রয়েছে
  • while fgযখন কোনও fgশূন্য-বহির্গমন স্থিতি নিয়ে বের হয় তখন লুপিং বন্ধ হবে

দুর্ভাগ্যক্রমে যখন ব্যাকগ্রাউন্ডে কোনও প্রক্রিয়া শূন্য-বহির্গমন স্থিতি থেকে প্রস্থান করে তখন এটি কেসটি পরিচালনা করবে না। (লুপটি অবিলম্বে শেষ হবে না it এটি পূর্ববর্তী প্রক্রিয়াগুলি শেষ হওয়ার জন্য অপেক্ষা করবে))


3

এখানে ইতিমধ্যে প্রচুর উত্তর রয়েছে, তবে আমি অবাক হয়েছি যে কেউ অ্যারে ব্যবহারের পরামর্শ দেয়নি বলে মনে হয় ... সুতরাং আমি যা করেছি তা এখানে - এটি ভবিষ্যতে কারও পক্ষে কার্যকর হতে পারে।

n=10 # run 10 jobs
c=0
PIDS=()

while true

    my_function_or_command &
    PID=$!
    echo "Launched job as PID=$PID"
    PIDS+=($PID)

    (( c+=1 ))

    # required to prevent any exit due to error
    # caused by additional commands run which you
    # may add when modifying this example
    true

do

    if (( c < n ))
    then
        continue
    else
        break
    fi
done 


# collect launched jobs

for pid in "${PIDS[@]}"
do
    wait $pid || echo "failed job PID=$pid"
done

3

এটি কাজ করে, @ হোভারহেল এর উত্তরের চেয়ে ভাল না হলে ঠিক যেমন ভাল হওয়া উচিত!

#!/usr/bin/env bash

set -m # allow for job control
EXIT_CODE=0;  # exit code of overall script

function foo() {
     echo "CHLD exit code is $1"
     echo "CHLD pid is $2"
     echo $(jobs -l)

     for job in `jobs -p`; do
         echo "PID => ${job}"
         wait ${job} ||  echo "At least one test failed with exit code => $?" ; EXIT_CODE=1
     done
}

trap 'foo $? $$' CHLD

DIRN=$(dirname "$0");

commands=(
    "{ echo "foo" && exit 4; }"
    "{ echo "bar" && exit 3; }"
    "{ echo "baz" && exit 5; }"
)

clen=`expr "${#commands[@]}" - 1` # get length of commands - 1

for i in `seq 0 "$clen"`; do
    (echo "${commands[$i]}" | bash) &   # run the command via bash in subshell
    echo "$i ith command has been issued as a background job"
done

# wait for all to finish
wait;

echo "EXIT_CODE => $EXIT_CODE"
exit "$EXIT_CODE"

# end

এবং অবশ্যই, আমি এই স্ক্রিপ্টটিকে অমর করে দিয়েছি, একটি এনপিএম প্রকল্পে, যা আপনাকে পরীক্ষার জন্য দরকারী সমান্তরালে বাশ কমান্ড চালাতে দেয়:

https://github.com/ORESoftware/generic-subshell


trap $? $$আমার কাছে প্রতিবারের জন্য চলমান ব্যাশ শেলের কাছে প্রস্থান কোড 0 এবং পিআইডি সেট করে বলে মনে হচ্ছে
inetknght

তুমি এ সম্পর্কে নিশ্চিত? নিশ্চিত না যে এটি বোঝা যায় কিনা।
আলেকজান্ডার মিলস

2

ফাঁদ আপনার বন্ধু। আপনি প্রচুর সিস্টেমে ইআরআর ফাঁদে ফেলতে পারেন। আপনি প্রতিটি কমান্ডের পরে কোনও অংশের কোড সম্পাদন করতে EXIT বা DEBUG এ ট্র্যাপ করতে পারেন।

এটি সমস্ত মানক সংকেত ছাড়াও।


1
দয়া করে কিছু উত্তর দিয়ে আপনার উত্তরটি বিস্তারিতভাবে বর্ণনা করতে পারেন।
εδιϲMεδιϲ

2
set -e
fail () {
    touch .failure
}
expect () {
    wait
    if [ -f .failure ]; then
        rm -f .failure
        exit 1
    fi
}

sleep 2 || fail &
sleep 2 && false || fail &
sleep 2 || fail
expect

দ্য set -eউপরের ব্যর্থতা উপর আপনার স্ক্রিপ্টটি স্টপ করে তোলে।

expect1কোনও সাবজব ব্যর্থ হলে ফিরে আসবে ।


2

ঠিক এই উদ্দেশ্যেই আমি একটি bashফাংশন লিখেছিলাম called:for

দ্রষ্টব্য : :forব্যর্থ ফাংশনটির প্রস্থান কোডটি কেবল সংরক্ষণ করে এবং ফেরত দেয় না, তবে সমস্ত সমান্তরাল চলমান ঘটনাকেও সমাপ্ত করে। এক্ষেত্রে যা প্রয়োজন হতে পারে না।

#!/usr/bin/env bash

# Wait for pids to terminate. If one pid exits with
# a non zero exit code, send the TERM signal to all
# processes and retain that exit code
#
# usage:
# :wait 123 32
function :wait(){
    local pids=("$@")
    [ ${#pids} -eq 0 ] && return $?

    trap 'kill -INT "${pids[@]}" &>/dev/null || true; trap - INT' INT
    trap 'kill -TERM "${pids[@]}" &>/dev/null || true; trap - RETURN TERM' RETURN TERM

    for pid in "${pids[@]}"; do
        wait "${pid}" || return $?
    done

    trap - INT RETURN TERM
}

# Run a function in parallel for each argument.
# Stop all instances if one exits with a non zero
# exit code
#
# usage:
# :for func 1 2 3
#
# env:
# FOR_PARALLEL: Max functions running in parallel
function :for(){
    local f="${1}" && shift

    local i=0
    local pids=()
    for arg in "$@"; do
        ( ${f} "${arg}" ) &
        pids+=("$!")
        if [ ! -z ${FOR_PARALLEL+x} ]; then
            (( i=(i+1)%${FOR_PARALLEL} ))
            if (( i==0 )) ;then
                :wait "${pids[@]}" || return $?
                pids=()
            fi
        fi
    done && [ ${#pids} -eq 0 ] || :wait "${pids[@]}" || return $?
}

ব্যবহার

for.sh:

#!/usr/bin/env bash
set -e

# import :for from gist: https://gist.github.com/Enteee/c8c11d46a95568be4d331ba58a702b62#file-for
# if you don't like curl imports, source the actual file here.
source <(curl -Ls https://gist.githubusercontent.com/Enteee/c8c11d46a95568be4d331ba58a702b62/raw/)

msg="You should see this three times"

:(){
  i="${1}" && shift

  echo "${msg}"

  sleep 1
  if   [ "$i" == "1" ]; then sleep 1
  elif [ "$i" == "2" ]; then false
  elif [ "$i" == "3" ]; then
    sleep 3
    echo "You should never see this"
  fi
} && :for : 1 2 3 || exit $?

echo "You should never see this"
$ ./for.sh; echo $?
You should see this three times
You should see this three times
You should see this three times
1

তথ্যসূত্র


1

আমি সম্প্রতি এটি ব্যবহার করেছি (আলনীটাককে ধন্যবাদ):

#!/bin/bash
# activate child monitoring
set -o monitor

# locking subprocess
(while true; do sleep 0.001; done) &
pid=$!

# count, and kill when all done
c=0
function kill_on_count() {
    # you could kill on whatever criterion you wish for
    # I just counted to simulate bash's wait with no args
    [ $c -eq 9 ] && kill $pid
    c=$((c+1))
    echo -n '.' # async feedback (but you don't know which one)
}
trap "kill_on_count" CHLD

function save_status() {
    local i=$1;
    local rc=$2;
    # do whatever, and here you know which one stopped
    # but remember, you're called from a subshell
    # so vars have their values at fork time
}

# care must be taken not to spawn more than one child per loop
# e.g don't use `seq 0 9` here!
for i in {0..9}; do
    (doCalculations $i; save_status $i $?) &
done

# wait for locking subprocess to be killed
wait $pid
echo

সেখান থেকে সহজেই এক্সট্রোপোলেট করা যায় এবং ট্রিগার (কোনও ফাইল স্পর্শ করুন, একটি সংকেত প্রেরণ করুন) এবং সেই ট্রিগারটির প্রতিক্রিয়া জানার জন্য গণনার মানদণ্ড (স্পর্শ করা ফাইলগুলি বা কোনও কিছু) পরিবর্তন করতে পারে can অথবা আপনি যদি শূন্য নন এমন কোনও 'আর' চান, কেবল সেভ_স্ট্যাটাস থেকে লকটি হত্যা করুন।


1

আমার এটির দরকার ছিল, তবে লক্ষ্য প্রক্রিয়াটি বর্তমান শেলের শিশু নয়, এক্ষেত্রে wait $PIDকাজ করে না। পরিবর্তে আমি নিম্নলিখিত বিকল্পটি পেয়েছি:

while [ -e /proc/$PID ]; do sleep 0.1 ; done

এটি প্রোফসের উপস্থিতির উপর নির্ভর করে , যা উপলব্ধ নাও হতে পারে (ম্যাক উদাহরণ হিসাবে এটি সরবরাহ করে না)। সুতরাং বহনযোগ্যতার জন্য, আপনি এর পরিবর্তে এটি ব্যবহার করতে পারেন:

while ps -p $PID >/dev/null ; do sleep 0.1 ; done

1

সিএফএলডি সিগন্যালটি আটকা পড়া কাজ করতে পারে না কারণ তারা যদি একই সাথে উপস্থিত হয় তবে আপনি কিছু সংকেত হারাতে পারেন।

#!/bin/bash

trap 'rm -f $tmpfile' EXIT

tmpfile=$(mktemp)

doCalculations() {
    echo start job $i...
    sleep $((RANDOM % 5)) 
    echo ...end job $i
    exit $((RANDOM % 10))
}

number_of_jobs=10

for i in $( seq 1 $number_of_jobs )
do
    ( trap "echo job$i : exit value : \$? >> $tmpfile" EXIT; doCalculations ) &
done

wait 

i=0
while read res; do
    echo "$res"
    let i++
done < "$tmpfile"

echo $i jobs done !!!

1

বেশিরভাগ সাব-প্রসেসের জন্য অপেক্ষা করার সমাধান এবং যখন তাদের মধ্যে কেউ শূন্য-স্থিতি স্থিতি কোড নিয়ে বের হয় তখন 'ওয়েট-এন' ব্যবহার করে

#!/bin/bash
wait_for_pids()
{
    for (( i = 1; i <= $#; i++ )) do
        wait -n $@
        status=$?
        echo "received status: "$status
        if [ $status -ne 0 ] && [ $status -ne 127 ]; then
            exit 1
        fi
    done
}

sleep_for_10()
{
    sleep 10
    exit 10
}

sleep_for_20()
{
    sleep 20
}

sleep_for_10 &
pid1=$!

sleep_for_20 &
pid2=$!

wait_for_pids $pid2 $pid1

স্থিতি কোড '127' অ-বিদ্যমান প্রক্রিয়াটির জন্য যার অর্থ শিশুটি সম্ভবত বেরিয়ে এসেছিল।


1

সমস্ত কাজের জন্য অপেক্ষা করুন এবং সর্বশেষ ব্যর্থতার কাজের প্রস্থান কোডটি ফিরিয়ে দিন। উপরের সমাধানগুলির বিপরীতে, এর জন্য পিড সংরক্ষণের প্রয়োজন নেই। শুধু বিজি দূরে, এবং অপেক্ষা করুন।

function wait_ex {
    # this waits for all jobs and returns the exit code of the last failing job
    ecode=0
    while true; do
        wait -n
        err="$?"
        [ "$err" == "127" ] && break
        [ "$err" != "0" ] && ecode="$err"
    done
    return $ecode
}

এটি কার্যকর হবে এবং নির্ভরযোগ্যভাবে আপনার কার্যকর হওয়া কমান্ডগুলি থেকে প্রথম ত্রুটি কোড দেবে যদি না এটি "কমান্ড পাওয়া যায় না" (কোড 127) হয়ে থাকে।
ড্রিভিকো

0

প্রক্রিয়াটির অপেক্ষা করার আগে প্রক্রিয়াটি সম্পূর্ণ হওয়ার ক্ষেত্রে এমন একটি মামলা থাকতে পারে। যদি আমরা ইতিমধ্যে সমাপ্ত প্রক্রিয়ার জন্য অপেক্ষা করতে শুরু করি তবে এটি ত্রুটি ট্রিগার করবে যেমন পিড এই শেলটির শিশু নয়। এই জাতীয় ঘটনা এড়াতে, নিম্নলিখিত ক্রিয়াটি প্রক্রিয়াটি সম্পূর্ণ কিনা তা অনুসন্ধানে ব্যবহার করা যেতে পারে:

isProcessComplete(){
PID=$1
while [ -e /proc/$PID ]
do
    echo "Process: $PID is still running"
    sleep 5
done
echo "Process $PID has finished"
}

0

আমি মনে করি যে সমান্তরালভাবে চাকরি চালানোর এবং স্থিতির জন্য যাচাই করার জন্য সবচেয়ে সোজা এগিয়ে থাকা উপায় অস্থায়ী ফাইলগুলি। ইতিমধ্যে দু'জনের অনুরূপ উত্তর রয়েছে (উদাহরণস্বরূপ নীটচে-জৌ এবং মগ 896)।

#!/bin/bash
rm -f fail
for i in `seq 0 9`; do
  doCalculations $i || touch fail &
done
wait 
! [ -f fail ]

উপরের কোডটি থ্রেড নিরাপদ নয়। আপনি যদি উদ্বিগ্ন হন যে উপরের কোডটি নিজেও একই সময়ে চলবে, তবে ব্যর্থতার মতো আরও একটি অনন্য ফাইল নাম ব্যবহার করা ভাল $$ $$ সর্বশেষ লাইনটি প্রয়োজনীয়তাটি পূরণ করার জন্য: "প্রস্থান প্রসেসগুলির কোনও কোড দিয়ে শেষ হয়, তখন প্রস্থান প্রস্থান কোড 1টি ফেরান!" আমি পরিষ্কার করার জন্য সেখানে একটি অতিরিক্ত প্রয়োজনীয়তা ছুড়েছি। এটি এটি এইভাবে লিখতে পরিষ্কার হতে পারে:

#!/bin/bash
trap 'rm -f fail.$$' EXIT
for i in `seq 0 9`; do
  doCalculations $i || touch fail.$$ &
done
wait 
! [ -f fail.$$ ] 

একাধিক কাজ থেকে ফলাফল সংগ্রহের জন্য এখানে একটি অনুরূপ স্নিপেট রয়েছে: আমি একটি অস্থায়ী ডিরেক্টরি তৈরি করি, একটি পৃথক ফাইলে সমস্ত সাব টাস্কের আউটপুটগুলি গল্প করি এবং তারপরে পর্যালোচনার জন্য সেগুলি ফেলে দেব। এটি আসলে প্রশ্নের সাথে মেলে না - আমি এটি বোনাস হিসাবে ফেলে দিচ্ছি:

#!/bin/bash
trap 'rm -fr $WORK' EXIT

WORK=/tmp/$$.work
mkdir -p $WORK
cd $WORK

for i in `seq 0 9`; do
  doCalculations $i >$i.result &
done
wait 
grep $ *  # display the results with filenames and contents

0

আমি প্রায় jobs -pপিআইডি সংগ্রহ করার জন্য ব্যবহারের ফাঁদে পড়েছিলাম , যা নীচে স্ক্রিপ্টে দেখানো হয়েছে, বাচ্চা ইতিমধ্যে বেরিয়ে এসে থাকলে কাজ করে না। আমি যে সমাধানটি গ্রহণ করেছি তা হ'ল wait -nএন বার কল করছিল , যেখানে এন আমার কাছে থাকা বাচ্চাদের সংখ্যা, যা আমি নির্বিচারে জানি।

#!/usr/bin/env bash

sleeper() {
    echo "Sleeper $1"
    sleep $2
    echo "Exiting $1"
    return $3
}

start_sleepers() {
    sleeper 1 1 0 &
    sleeper 2 2 $1 &
    sleeper 3 5 0 &
    sleeper 4 6 0 &
    sleep 4
}

echo "Using jobs"
start_sleepers 1

pids=( $(jobs -p) )

echo "PIDS: ${pids[*]}"

for pid in "${pids[@]}"; do
    wait "$pid"
    echo "Exit code $?"
done

echo "Clearing other children"
wait -n; echo "Exit code $?"
wait -n; echo "Exit code $?"

echo "Waiting for N processes"
start_sleepers 2

for ignored in $(seq 1 4); do
    wait -n
    echo "Exit code $?"
done

আউটপুট:

Using jobs
Sleeper 1
Sleeper 2
Sleeper 3
Sleeper 4
Exiting 1
Exiting 2
PIDS: 56496 56497
Exiting 3
Exit code 0
Exiting 4
Exit code 0
Clearing other children
Exit code 0
Exit code 1
Waiting for N processes
Sleeper 1
Sleeper 2
Sleeper 3
Sleeper 4
Exiting 1
Exiting 2
Exit code 0
Exit code 2
Exiting 3
Exit code 0
Exiting 4
Exit code 0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.