প্রক্রিয়া প্রতিস্থাপন ব্যবহার করার সময় আমি কীভাবে প্রস্থান কোড / হ্যান্ডেল ত্রুটিগুলি সঠিকভাবে ক্যাপচার করব?


13

আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা এসও-তে প্রশ্নোত্তর থেকে নেওয়া নিম্নলিখিত পদ্ধতিটি ব্যবহার করে ফাইলের নামগুলিকে অ্যারেতে পার্স করে :

unset ARGS
ARGID="1"
while IFS= read -r -d $'\0' FILE; do
    ARGS[ARGID++]="$FILE"
done < <(find "$@" -type f -name '*.txt' -print0)

এটি দুর্দান্ত কাজ করে এবং সকল প্রকারের ফাইলের বিভিন্নতা পুরোপুরি পরিচালনা করে। কখনও কখনও, তবে আমি স্ক্রিপ্টে একটি অ-বিদ্যমান ফাইলটি পাস করব, যেমন:

$ findscript.sh existingfolder nonexistingfolder
find: `nonexistingfile': No such file or directory
...

স্বাভাবিক পরিস্থিতিতে আমার কাছে স্ক্রিপ্টটি প্রস্থান কোডের মতো কিছু দিয়ে ক্যাপচার করত RET=$?এবং কীভাবে এগিয়ে যায় তা স্থির করতে এটি ব্যবহার করে। এটি উপরের প্রক্রিয়া বিকল্পের সাথে কাজ করে বলে মনে হচ্ছে না।

এই জাতীয় ক্ষেত্রে সঠিক পদ্ধতি কি? আমি কীভাবে রিটার্ন কোডটি ক্যাপচার করব? প্রতিস্থাপন প্রক্রিয়াতে কিছু ভুল হয়েছে কিনা তা নির্ধারণের জন্য আরও কি আরও উপযুক্ত উপায় আছে?

উত্তর:


5

স্ট্যান্ডআউটের মাধ্যমে এর রিটার্ন প্রতিধ্বনিত করে আপনি সহজেই যে কোনও সাব-সেলড প্রক্রিয়া থেকে রিটার্ন পেতে পারেন। প্রক্রিয়া প্রতিস্থাপনের ক্ষেত্রেও একই কথা:

while IFS= read -r -d $'\0' FILE || 
    ! return=$FILE
do    ARGS[ARGID++]="$FILE"
done < <(find . -type f -print0; printf "$?")

যদি আমি এটি চালিয়ে থাকি তবে একেবারে শেষ লাইন - (বা \0কেস হিসাবে বিস্মিত বিভাগটি হতে পারে)find এর রিটার্নের স্থিতি হতে চলেছে । read1 ফিরে যখন এটি একটি ফাইলের শেষে পায় যাচ্ছে - তাই শুধুমাত্র সময় $returnসেট করা হয় $FILEজন্য তথ্য খুব গত কিছুক্ষনের মধ্যে পড়া হয়।

আমি printfঅতিরিক্ত \newline যোগ করা থেকে বিরত রাখতে ব্যবহার করি - এটি গুরুত্বপূর্ণ কারণ এমনকি readনিয়মিত একটি সঞ্চালিত - এমন একটি যেখানে আপনি \0NULs এ ছাঁটাই করেন না - যখন কেবলমাত্র এটি পড়েছে এমন ডেটা শেষ না হয় এমন ক্ষেত্রে 0 এর বাইরে অন্যটি ফিরে আসতে চলেছে একটি \newline সুতরাং যদি আপনার শেষ লাইনটি কোনও \newline দিয়ে শেষ না হয় তবে আপনার পঠনযোগ্য ভেরিয়েবলের সর্বশেষ মানটি আপনার রিটার্ন হতে চলেছে।

কমান্ড উপরের দিকে এবং তারপরে:

echo "$return"

আউটপুট

0

এবং আমি যদি প্রক্রিয়াটির বিকল্প অংশটি পরিবর্তন করি ...

...
done < <(! find . -type f -print0; printf "$?")
echo "$return"

আউটপুট

1

আরও সাধারণ বিক্ষোভ:

printf \\n%s list of lines printed to pipe |
while read v || ! echo "$v"
do :; done

আউটপুট

pipe

এবং প্রকৃতপক্ষে, আপনি যে রিটার্নটি চান তা যতক্ষণ না আপনি প্রক্রিয়া প্রতিস্থাপনের মধ্য থেকে স্টাডাউটকে লিখতে সর্বশেষ জিনিসটি - বা যে কোনও সাব-সেলড প্রক্রিয়া যা থেকে আপনি এইভাবে পড়েছেন - তখন $FILEসর্বদা আপনি যখন চান তখন ফিরে আসার অবস্থা হবে মাধ্যমে হয়। এবং তাই || ! return=...অংশটি কঠোরভাবে প্রয়োজনীয় নয় - এটি কেবল ধারণাটি প্রদর্শনের জন্য ব্যবহৃত হয়।


5

প্রক্রিয়া প্রতিস্থাপনের প্রক্রিয়াগুলি অ্যাসিনক্রোনাস হয়: শেল সেগুলি চালু করে এবং তারপরে তারা কখন মারা যায় তা সনাক্ত করার কোনও উপায় দেয় না। সুতরাং আপনি প্রস্থান স্থিতি পেতে সক্ষম হবেন না।

আপনি কোনও ফাইলের প্রস্থান স্থিতি লিখতে পারেন, তবে এটি সাধারণভাবে আনাড়ি কারণ ফাইলটি কখন লেখা হয় তা আপনি জানেন না। এখানে, ফাইলটি লুপ শেষ হওয়ার সাথে সাথেই লেখা হয়, সুতরাং এটির জন্য অপেক্ষা করা যুক্তিসঙ্গত।

 < <(find …; echo $? >find.status.tmp; mv find.status.tmp find.status)
while ! [ -e find.status ]; do sleep 1; done
find_status=$(cat find.status; rm find.status)

অন্য পদ্ধতির নামযুক্ত পাইপ এবং একটি পটভূমি প্রক্রিয়া (যা আপনি এটি করতে পারেন wait) ব্যবহার করা।

mkfifo find_pipe
find  >find_pipe &
find_pid=$!
 <find_pipe
wait $find_pid
find_status=$?

যদি উভয়ই পদ্ধতির উপযোগী না হয় তবে আমি মনে করি আপনার আরও দক্ষ ভাষার জন্য দরকার, যেমন পার্ল, পাইথন বা রুবি।


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

2

একটি কপ্রোসেস ব্যবহার করুন । coprocবিল্টিন ব্যবহার করে আপনি একটি সাবপ্রসেস শুরু করতে পারেন, এর আউটপুটটি পড়তে পারেন এবং এর প্রস্থান স্থিতিটি পরীক্ষা করতে পারেন:

coproc LS { ls existingdir; }
LS_PID_=$LS_PID
while IFS= read i; do echo "$i"; done <&"$LS"
wait "$LS_PID_"; echo $?

ডিরেক্টরি উপস্থিত না থাকলে, waitএকটি শূন্য নয় স্থিতি কোড সহ প্রস্থান করবে।

পিআইডিকে বর্তমানে অন্য ভেরিয়েবলে অনুলিপি করা প্রয়োজন কারণ ডাকা $LS_PIDহওয়ার আগেই সেটটি সেট করা হবে না wait। দেখুন ব্যাশ unsets _PID পরিবর্তনশীল আগে আমি coproc অপেক্ষা করতে পারেন * বিস্তারিত জানার জন্য।


1
আমি কৌতূহল করছি যে কখন <& "$ LS" বনাম পঠন-$ এলএস ব্যবহার করবে? - ধন্যবাদ
ব্রায়ান ক্রিসম্যান

1
@ ব্রায়ান ক্রিসম্যান এই পরিস্থিতিতে সম্ভবত কখনও নয়। read -uঠিক পাশাপাশি কাজ করা উচিত। উদাহরণটি জেনেরিক হওয়া এবং দেখানো ছিল কীভাবে কপ্রোসেসের আউটপুট অন্য কমান্ডে পাইপ করা যায়।
ফিউমুরমেল

1

একটি পদ্ধতির হ'ল:

status=0
token="WzNZY3CjqF3qkasn"    # some random string
while read line; do
    if [[ "$line" =~ $token:([[:digit:]]+) ]]; then
        status="${BASH_REMATCH[1]}"
    else
        echo "$line"
    fi
done < <(command; echo "$token:$?")
echo "Return code: $status"

কমান্ডটি শেষ হওয়ার পরে এলোমেলো টোকেনের সাথে প্রস্থান স্থিতি প্রতিধ্বনি করা এবং তারপরে প্রস্থান স্থিতি সন্ধান এবং নিষ্কাশন করার জন্য ব্যাশ নিয়মিত এক্সপ্রেশন ব্যবহার করা উচিত। টোকেনটি আউটপুটটিতে সন্ধান করার জন্য একটি অনন্য স্ট্রিং তৈরি করতে ব্যবহৃত হয়।

এটি সাধারণ প্রোগ্রামিং অর্থে এটি করার সর্বোত্তম উপায় নয় তবে এটি ব্যাশে পরিচালনা করার সবচেয়ে কম বেদনাদায়ক উপায় হতে পারে।

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