সমান্তরাল পটভূমি প্রক্রিয়াগুলির প্রস্থান কোড সংগ্রহ করুন (উপ শেলস)


18

বলুন আমাদের মতো বাশ স্ক্রিপ্ট রয়েছে:

echo "x" &
echo "y" &
echo "z" &
.....
echo "Z" &
wait

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

আমি একটি জেনেরিক সমাধানের সন্ধান করছি (সমান্তরালভাবে চালানোর জন্য আমার কাছে অজানা / গতিশীল সংখ্যা রয়েছে) have


1
আমি আপনাকে পরামর্শ দিচ্ছি যে এটি আপনি কী চান তা নির্ধারণ করুন এবং তারপরে একটি নতুন প্রশ্ন জিজ্ঞাসা করুন, আপনি যে আচরণটি খুঁজছেন তা সম্পর্কে স্পষ্ট হয়ে উঠার চেষ্টা করছি (সম্ভবত সিউডোকোড বা আরও বড় উদাহরণ সহ)।
মাইকেল হোমার

3
আমি আসলে মনে করি প্রশ্নটি এখন ভাল - আমার কাছে সাব-প্রসেসের একটি গতিশীল সংখ্যা রয়েছে। আমার সমস্ত প্রস্থান কোড সংগ্রহ করতে হবে। এখানেই শেষ.
আলেকজান্ডার মিলস

উত্তর:


6

আলেকজান্ডার মিলস যা হ্যান্ডেলজবস ব্যবহার করে তার উত্তর আমাকে দুর্দান্ত সূচনা পয়েন্ট দিয়েছে, তবে আমাকে এই ত্রুটিটি দিয়েছে

সতর্কতা: রান_পেন্ডিং_ট্রেপস: ট্র্যাপ_লিস্টের খারাপ মান [17]: 0x461010

যা বাশ রেস-কন্ডিশনের সমস্যা হতে পারে

পরিবর্তে আমি কেবলমাত্র প্রতিটি সন্তানের পিড সঞ্চয় করেছি এবং অপেক্ষা করেছি এবং প্রতিটি সন্তানের জন্য বিশেষভাবে প্রস্থান কোড পেয়েছি। আমি এই ক্লিনারটি ফাংশনগুলিতে সাব-প্রসেসিগুলি ছড়িয়ে দেওয়া এবং পিতা-মাতার প্রক্রিয়ার জন্য অপেক্ষা করার ঝুঁকি এড়ানো যেখানে আমি সন্তানের জন্য অপেক্ষা করতে চেয়েছি, সে ক্ষেত্রে এটি পরিষ্কার পেয়েছি find এটি স্পষ্ট হয় কী ঘটেছিল কারণ এটি ফাঁদ ব্যবহার না করে।

#!/usr/bin/env bash

# it seems it does not work well if using echo for function return value, and calling inside $() (is a subprocess spawned?) 
function wait_and_get_exit_codes() {
    children=("$@")
    EXIT_CODE=0
    for job in "${children[@]}"; do
       echo "PID => ${job}"
       CODE=0;
       wait ${job} || CODE=$?
       if [[ "${CODE}" != "0" ]]; then
           echo "At least one test failed with exit code => ${CODE}" ;
           EXIT_CODE=1;
       fi
   done
}

DIRN=$(dirname "$0");

commands=(
    "{ echo 'a'; exit 1; }"
    "{ echo 'b'; exit 0; }"
    "{ echo 'c'; exit 2; }"
    )

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

children_pids=()
for i in `seq 0 "$clen"`; do
    (echo "${commands[$i]}" | bash) &   # run the command via bash in subshell
    children_pids+=("$!")
    echo "$i ith command has been issued as a background job"
done
# wait; # wait for all subshells to finish - its still valid to wait for all jobs to finish, before processing any exit-codes if we wanted to
#EXIT_CODE=0;  # exit code of overall script
wait_and_get_exit_codes "${children_pids[@]}"

echo "EXIT_CODE => $EXIT_CODE"
exit "$EXIT_CODE"
# end

শীতল, আমি মনে করি for job in "${childen[@]}"; doহওয়া উচিত for job in "${1}"; doস্বচ্ছতার জন্য, যদিও
আলেকজান্ডার মিলস

এই স্ক্রিপ্টটি নিয়ে আমার কেবল উদ্বেগটি হ'ল তা children_pids+=("$!")হ'ল যদি সাব শেলের জন্য পছন্দসই পিডটি ক্যাপচার করা হয়।
আলেকজান্ডার মিলস

1
আমি "$ {1}" দিয়ে পরীক্ষা করেছি এবং এটি কার্যকর হয় না। আমি ফাংশনে একটি অ্যারে পাস করছি, এবং সম্ভবত এটির জন্য বাশগুলিতে বিশেষ মনোযোগ প্রয়োজন। $! এটি সর্বশেষ প্রসারিত কাজের মূর্খতা রয়েছে , দেখুন tldp.org/LDP/abs/html/internvariables.html এটি আমার পরীক্ষায় সঠিকভাবে কাজ করছে বলে মনে হচ্ছে, এবং এখন আমি অনারاد ক্যাশে_ডিয়ার স্ক্রিপ্টটিতে ব্যবহার করছি এবং এটি মনে হচ্ছে এটির কাজ আমি ব্যাশ ব্যবহার করছি 4.4.12।
আরবার্গ

হ্যাঁ মনে হচ্ছে আপনি ঠিক আছেন
আলেকজান্ডার মিলস

20

waitএকটি পিআইডি ব্যবহার করুন , যা এটি করবে:

শিশু প্রক্রিয়া প্রতিটি প্রসেসের ID দ্বারা উল্লিখিত পর্যন্ত অপেক্ষা PID অথবা চাকরি স্পেসিফিকেশন jobspec প্রস্থানের এবং রিটার্ন গত কমান্ডের প্রস্থান অবস্থা অপেক্ষা করলো।

আপনার প্রতিটি প্রসেসের পিআইডি সংরক্ষণ করতে হবে:

echo "x" & X=$!
echo "y" & Y=$!
echo "z" & Z=$!

আপনি স্ক্রিপ্টে কাজের নিয়ন্ত্রণ সক্ষম করতে এবং set -mএকটি %nজবস্পেক ব্যবহার করতে পারেন , তবে আপনি প্রায় অবশ্যই চান না - কাজের নিয়ন্ত্রণের অনেকগুলি অন্যান্য পার্শ্ব প্রতিক্রিয়া রয়েছে

waitপ্রক্রিয়াটি শেষ হওয়ার সাথে সাথে একই কোডটি ফিরিয়ে দেবে। আপনি wait $Xচূড়ান্ত কোডটি অ্যাক্সেস করতে পরবর্তী কোনও (যুক্তিসঙ্গত) বিন্দুতে ব্যবহার করতে পারেন $?বা কেবল এটি সত্য / মিথ্যা হিসাবে ব্যবহার করতে পারেন:

echo "x" & X=$!
echo "y" & Y=$!
...
wait $X
echo "job X returned $?"

wait কমান্ডটি সম্পূর্ণ না হওয়া অবধি বিরতি দেবে যদি তা ইতিমধ্যে না হয়ে থাকে।

আপনি যদি এ জাতীয় স্টলিং এড়াতে চান, আপনি একটি trapচালুSIGCHLD করতে পারেন , অবসানের সংখ্যা গণনা করতে পারেন এবং সমস্তগুলি শেষ waitহয়ে গেলে একবারে হ্যান্ডেল করতে পারেন । আপনি সম্ভবত waitপ্রায় সব সময় একা ব্যবহার করে পালাতে পারেন ।


1
ওহ, দুঃখিত, আমার সমান্তরালভাবে এই সাবশেলগুলি চালানো দরকার, আমি সেই প্রশ্নের মধ্যে উল্লেখ করব ...
আলেকজান্ডার মিলস

কিছু নয়, সম্ভবত এটি আমার সেটআপটির সাথে কাজ করে ... আপনার কোডটিতে ওয়েটিং কমান্ডটি কোথায় আসে? আমি অনুসরণ করি না
আলেকজান্ডার মিলস

1
@AlexanderMills তারা হয় সমান্তরাল চলমান। আপনার যদি এগুলির একটি পরিবর্তনশীল সংখ্যা থাকে তবে একটি অ্যারে ব্যবহার করুন। (যেমন, এখানে যা এখানে সদৃশ হতে পারে)।
মাইকেল হোমার

হ্যাঁ ধন্যবাদ আমি এটি যাচাই করব, যদি ওয়েট কমান্ড আপনার উত্তরটির সাথে সম্পর্কিত হয়, তবে দয়া করে এটি যুক্ত করুন
আলেকজান্ডার মিলস

আপনি wait $Xপরে যেকোন (যুক্তিসঙ্গত) দৌড়ে যান।
মাইকেল হোমার

5

কমান্ডগুলি সনাক্ত করার জন্য আপনার যদি ভাল উপায় থাকে তবে আপনি তাদের প্রস্থান কোডটি একটি টিএমপি ফাইলে মুদ্রণ করতে এবং তারপরে আপনার আগ্রহী নির্দিষ্ট ফাইলটি অ্যাক্সেস করতে পারেন:

#!/bin/bash

for i in `seq 1 5`; do
    ( sleep $i ; echo $? > /tmp/cmd__${i} ) &
done

wait

for i in `seq 1 5`; do # or even /tmp/cmd__*
    echo "process $i:"
    cat /tmp/cmd__${i}
done

টিএমপি ফাইলগুলি সরাতে ভুলবেন না।


4

একটি ব্যবহার করুন compound command- বন্ধনী মধ্যে বিবৃতি রাখুন:

( echo "x" ; echo X: $? ) &
( true ; echo TRUE: $? ) &
( false ; echo FALSE: $? ) &

আউটপুট দেবে

x
X: 0
TRUE: 0
FALSE: 1

সমান্তরালভাবে বেশ কয়েকটি কমান্ড চালানোর জন্য একটি ভিন্ন উপায় হ'ল GNU সমান্তরাল ব্যবহার করে । চালানোর জন্য কমান্ডগুলির একটি তালিকা তৈরি করুন এবং সেগুলি ফাইলে রাখুন list:

cat > list
sleep 2 ; exit 7
sleep 3 ; exit 55
^D

সমান্তরালভাবে সমস্ত কমান্ড চালান এবং ফাইলের প্রস্থান কোডগুলি সংগ্রহ করুন job.log:

cat list | parallel -j0 --joblog job.log
cat job.log

এবং আউটপুটটি হ'ল:

Seq     Host    Starttime       JobRuntime      Send    Receive Exitval Signal  Command
1       :       1486892487.325       1.976      0       0       7       0       sleep 2 ; exit 7
2       :       1486892487.326       3.003      0       0       55      0       sleep 3 ; exit 55

ঠিক আছে ধন্যবাদ, এটিকে উদার করার কোনও উপায় আছে? আমার কাছে কেবল 3 টি উপ-প্রক্রিয়া নেই, আমার কাছে জেড সাব প্রসেস রয়েছে।
আলেকজান্ডার মিলস

আমি জেনেরিক সমাধানের সন্ধান করছি বলে প্রতিবিম্বিত করতে আমি আসল প্রশ্নটি আপডেট করেছি, ধন্যবাদ
আলেকজান্ডার মিলস

উদারকরণের একটি উপায় লুপিং কনস্ট্রাক্ট ব্যবহার করা হতে পারে?
আলেকজান্ডার মিলস

Looping? আপনার কাছে আদেশগুলির একটি নির্দিষ্ট তালিকা রয়েছে বা এটি ব্যবহারকারী দ্বারা নিয়ন্ত্রিত? আমি নিশ্চিত নই যে আপনি যা করার চেষ্টা করছেন তা আমি বুঝতে পেরেছি তবে সম্ভবত PIPESTATUSএটি আপনার যাচাই করা উচিত। এটি seq 10 | gzip -c > seq.gz ; echo ${PIPESTATUS[@]}প্রত্যাবর্তন করে 0 0(প্রথম এবং শেষ কমান্ড থেকে প্রস্থান কোড)।
hschou

হ্যাঁ মূলত ব্যবহারকারী দ্বারা নিয়ন্ত্রিত
আলেকজান্ডার মিলস

2

এটি আপনি জেনেরিক স্ক্রিপ্টটি সন্ধান করছেন। আপনার কমান্ডগুলি কেবলমাত্র উদ্ধৃতিতে রয়েছে তার অর্থ হ'ল যার অর্থ আপনার আইডিইয়ের মাধ্যমে সিনট্যাক্স হাইলাইট করা সত্যিই কাজ করবে না। অন্যথায়, আমি অন্যান্য উত্তরগুলির কয়েকটি চেষ্টা করেছি এবং এটি সেরা। এই উত্তরটি wait <pid>@ মিশেল দ্বারা প্রদত্ত ব্যবহারের ধারণাটিকে অন্তর্ভুক্ত করে তবে trapকমান্ডটি ব্যবহার করে আরও একধাপ এগিয়ে যায় যা সেরা বলে মনে হয়।

#!/usr/bin/env bash

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

function handleJobs() {
     for job in `jobs -p`; do
         echo "PID => ${job}"
         CODE=0;
         wait ${job} || CODE=$?
         if [[ "${CODE}" != "0" ]]; then
         echo "At least one test failed with exit code => ${CODE}" ;
         EXIT_CODE=1;
         fi
     done
}

trap 'handleJobs' CHLD  # trap command is the key part
DIRN=$(dirname "$0");

commands=(
    "{ echo 'a'; exit 1; }"
    "{ echo 'b'; exit 0; }"
    "{ echo 'c'; exit 2; }"
)

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; # wait for all subshells to finish

echo "EXIT_CODE => $EXIT_CODE"
exit "$EXIT_CODE"
# end

আমাকে সঠিক পথে পৌঁছে দেওয়ার জন্য @ মাইকেল মেশিনকে ধন্যবাদ জানাই, তবে trapকমান্ডটি ব্যবহার করা এএএফএসিটি সেরা পন্থা।


1
আপনি যখন প্রস্থান করবেন তখন বাচ্চাদের প্রস্থান করার সময় প্রক্রিয়া করার জন্য আপনি SIGCHLD ট্র্যাপ ব্যবহার করতে পারেন যেমন স্থিতি ছাপানো printing বা একটি অগ্রগতি কাউন্টার আপডেট করে: একটি ফাংশন ঘোষণা করুন তারপরে "ট্র্যাপ ফাংশন_নাম সিএইচএলডি" ব্যবহার করুন যদিও এটির জন্য একটি ইন্টারঅ্যাক্টিভ শেল, যেমন সম্ভবত "সেট-এম" চালু করার জন্য একটি বিকল্পের প্রয়োজন হতে পারে
চুনকো

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

@ চুনকো ধন্যবাদ! এটি একটি ভাল তথ্য, আপনি সম্ভবত যেটিকে সবচেয়ে ভাল বলে তার উত্তরটি আপডেট করতে পারেন?
আলেকজান্ডার মিলস

ধন্যবাদ @ চুনকো, ফাঁদ আরও ভাল কাজ করে, আপনি ঠিক বলেছেন। অপেক্ষার সাথে <পিড>, আমি হ্রাস পেয়েছি।
আলেকজান্ডার মিলস

আপনি কীভাবে ব্যাখ্যা করতে পারেন যে আপনি এবং কেন বিশ্বাস করেন যে ফাঁদ সহ সংস্করণটি এটি ব্যতীত তার চেয়ে ভাল? (আমি বিশ্বাস করি যে এটি এর চেয়ে ভাল নয়, এবং এটি আরও খারাপ, কারণ এটি কোনও লাভ ছাড়া আরও জটিল))
স্কট

1

@ রোলফের উত্তরের আরও একটি পরিবর্তন:

প্রস্থান স্থিতি সংরক্ষণের আর একটি উপায় এরকম কিছু হবে

mkdir /tmp/status_dir

এবং তারপরে প্রতিটি স্ক্রিপ্ট আছে

script_name="${0##*/}"  ## strip path from script name
tmpfile="/tmp/status_dir/${script_name}.$$"
do something
rc=$?
echo "$rc" > "$tmpfile"

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

এমনকী কিছু করে আপনি প্রতিটি স্ক্রিপ্ট থেকে একাধিক স্থিতি সংরক্ষণ করতে পারেন

tmpfile="$(/bin/mktemp -q "/tmp/status_dir/${script_name}.$$.XXXXXX")"

যা আগের মতো ফাইল তৈরি করে তবে এতে একটি অনন্য এলোমেলো স্ট্রিং যুক্ত হয়।

অথবা, আপনি একই স্থানে আরও স্থিতির তথ্য সংযোজন করতে পারেন।


1

script3নিষ্পন্ন করা হবে শুধুমাত্র যদি script1এবং script2সফল হয় এবং script1এবং script2সমান্তরাল ভাবে মৃত্যুদন্ড কার্যকর করা হবে:

./script1 &
process1=$!

./script2 &
process2=$!

wait $process1
rc1=$?

wait $process2
rc2=$?

if [[ $rc1 -eq 0 ]] && [[ $rc2 -eq 0  ]];then
./script3
fi

আফ্রিএইচসিটি, এটি মাইকেল হোমের উত্তরের পুনঃস্থাপন ছাড়া আর কিছুই নয় ।
স্কট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.