আমার দুটি প্রক্রিয়া আছে foo
এবং bar
, পাইপের সাথে যুক্ত:
$ foo | bar
bar
সর্বদা 0 থেকে প্রস্থান করে; আমি এর প্রস্থান কোড আগ্রহী foo
। এটি পেতে কোনও উপায় আছে?
আমার দুটি প্রক্রিয়া আছে foo
এবং bar
, পাইপের সাথে যুক্ত:
$ foo | bar
bar
সর্বদা 0 থেকে প্রস্থান করে; আমি এর প্রস্থান কোড আগ্রহী foo
। এটি পেতে কোনও উপায় আছে?
উত্তর:
আপনি যদি ব্যবহার করেন তবে আপনি পাইপলাইনের প্রতিটি উপাদানটির প্রস্থান স্থিতি পেতে অ্যারে ভেরিয়েবলটি bash
ব্যবহার করতে পারেন PIPESTATUS
।
$ false | true
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
1 0
আপনি যদি ব্যবহার করেন তবে zsh
তাদের অ্যারে বলা হয় pipestatus
(কেস ম্যাটার্স!) এবং অ্যারে সূচকগুলি এক থেকে শুরু হয়:
$ false | true
$ echo "${pipestatus[1]} ${pipestatus[2]}"
1 0
মানগুলি হারাবে না এমনভাবে একটি ফাংশনের মধ্যে তাদের একত্রিত করতে:
$ false | true
$ retval_bash="${PIPESTATUS[0]}" retval_zsh="${pipestatus[1]}" retval_final=$?
$ echo $retval_bash $retval_zsh $retval_final
1 0
উপরের চালনা করুন bash
বা zsh
আপনি একই ফলাফল পাবেন; শুধুমাত্র একটি retval_bash
এবং retval_zsh
সেট করা হবে। অন্যটি ফাঁকা থাকবে। এটি কোনও ফাংশনটি দিয়ে শেষ হতে দেয় return $retval_bash $retval_zsh
(উদ্ধৃতিগুলির অভাবটি নোট করুন!)।
pipestatus
zsh এ। দুর্ভাগ্যক্রমে অন্যান্য শেলগুলিতে এই বৈশিষ্ট্যটি নেই।
echo "$pipestatus[1]" "$pipestatus[2]"
।
if [ `echo "${PIPESTATUS[@]}" | tr -s ' ' + | bc` -ne 0 ]; then echo FAIL; fi
এটি করার 3 টি সাধারণ উপায় রয়েছে:
প্রথম উপায়টি pipefail
বিকল্প ( ksh
, zsh
বা bash
) সেট করা । এটি সবচেয়ে সহজ এবং এটি যা করে তা $?
অ-শূন্য থেকে বেরিয়ে আসার জন্য শেষ প্রোগ্রামের প্রস্থান কোডে প্রস্থান স্থিতি নির্ধারণ করে (বা সমস্ত সফলভাবে উপস্থিত থাকলে শূন্য)।
$ false | true; echo $?
0
$ set -o pipefail
$ false | true; echo $?
1
বাশ-এ $PIPESTATUS
( $pipestatus
ইন zsh
) নামে একটি অ্যারে ভেরিয়েবল রয়েছে যা সর্বশেষ পাইপলাইনে সমস্ত প্রোগ্রামের প্রস্থান স্থিতি ধারণ করে।
$ true | true; echo "${PIPESTATUS[@]}"
0 0
$ false | true; echo "${PIPESTATUS[@]}"
1 0
$ false | true; echo "${PIPESTATUS[0]}"
1
$ true | false; echo "${PIPESTATUS[@]}"
0 1
আপনার প্রয়োজনীয় পাইপলাইনে নির্দিষ্ট মান পেতে আপনি তৃতীয় কমান্ড উদাহরণটি ব্যবহার করতে পারেন।
এটি সমাধানগুলির সবচেয়ে অপ্রয়োজনীয়। প্রতিটি কমান্ড পৃথকভাবে চালান এবং স্থিতি ক্যাপচার
$ OUTPUT="$(echo foo)"
$ STATUS_ECHO="$?"
$ printf '%s' "$OUTPUT" | grep -iq "bar"
$ STATUS_GREP="$?"
$ echo "$STATUS_ECHO $STATUS_GREP"
0 1
ksh
, তবে এটির ম্যানপেজের উপর এক সংক্ষিপ্ত দৃষ্টিকোণ থেকে, এটি সমর্থন করে না $PIPESTATUS
বা এর অনুরূপ কিছু দেয় না । এটি pipefail
যদিও বিকল্পটি সমর্থন করে ।
LOG=$(failed_command | successful_command)
এই সমাধানটি ব্যাশ নির্দিষ্ট বৈশিষ্ট্য বা অস্থায়ী ফাইলগুলি ব্যবহার না করেই কাজ করে। বোনাস: শেষে প্রস্থান স্থিতি আসলে একটি প্রস্থান স্থিতি এবং কোনও ফাইলে কিছু স্ট্রিং নয়।
পরিস্থিতি:
someprog | filter
আপনি থেকে প্রস্থান স্থিতি someprog
এবং আউটপুট চান filter
।
এখানে আমার সমাধান:
((((someprog; echo $? >&3) | filter >&4) 3>&1) | (read xs; exit $xs)) 4>&1
এই কনস্ট্রাক্টের ফলাফলটি স্ট্রাউট filter
হিসাবে কনস্ট্রাক্ট এবং স্ট্রাউট স্ট্যাটাস someprog
হিসাবে কনস্ট্রাক্টের প্রস্থান স্থিতি হিসাবে।
এই কনস্ট্রাক্টটি {...}
সাব-শেলের পরিবর্তে সাধারণ কমান্ড গ্রুপিংয়ের সাথেও কাজ করে (...)
। সাবশেলের কিছু জড়িত রয়েছে, অন্যদের মধ্যে পারফরম্যান্স ব্যয়, যা আমাদের এখানে প্রয়োজন নেই। আরও বিশদের জন্য সূক্ষ্ম বাশ ম্যানুয়ালটি পড়ুন: https://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html
{ { { { someprog; echo $? >&3; } | filter >&4; } 3>&1; } | { read xs; exit $xs; } } 4>&1
দুর্ভাগ্যক্রমে বাশ ব্যাকরণের জন্য কোঁকড়া ধনুর্বন্ধনীগুলির জন্য ফাঁকা স্থান এবং সেমিকোলন প্রয়োজন যাতে নির্মাণ আরও অনেক প্রশস্ত হয়।
এই পাঠ্যের বাকী অংশের জন্য আমি সাব-শেল রূপটি ব্যবহার করব।
উদাহরণ someprog
এবং filter
:
someprog() {
echo "line1"
echo "line2"
echo "line3"
return 42
}
filter() {
while read line; do
echo "filtered $line"
done
}
((((someprog; echo $? >&3) | filter >&4) 3>&1) | (read xs; exit $xs)) 4>&1
echo $?
উদাহরণ আউটপুট:
filtered line1
filtered line2
filtered line3
42
দ্রষ্টব্য: শিশু প্রক্রিয়া পিতামাতার কাছ থেকে খোলা ফাইল বর্ণনাকারীদের উত্তরাধিকার সূত্রে পায়। এর অর্থ someprog
উন্মুক্ত ফাইল বর্ণনাকারী 3 এবং 4 উত্তরাধিকার সূত্রে প্রাপ্ত হবে If যদি someprog
বিবরণী 3 ফাইল লিখতে থাকে তবে সেটি প্রস্থান স্থিতিতে পরিণত হবে। আসল প্রস্থান স্থিতি এড়ানো হবে কারণ read
শুধুমাত্র একবার পড়বে ।
আপনি যদি উদ্বেগ প্রকাশ করেন যে আপনার someprog
সম্ভবত 3 বা 4 ফাইল বিবরণীতে লিখতে পারে তবে কল করার আগে ফাইল বর্ণনাকারী বন্ধ করে দেওয়া ভাল someprog
।
(((((exec 3>&- 4>&-; someprog); echo $? >&3) | filter >&4) 3>&1) | (read xs; exit $xs)) 4>&1
exec 3>&- 4>&-
সামনে someprog
চালানোর আগে ফাইল বর্ণনাকারী বন্ধ someprog
তাই someprog
ঐ ফাইল বর্ণনাকারী কেবল কোন অস্তিত্ব নেই।
এটিও এভাবে লেখা যেতে পারে: someprog 3>&- 4>&-
ধাপে ধাপে নির্মাণের ব্যাখ্যা:
( ( ( ( someprog; #part6
echo $? >&3 #part5
) | filter >&4 #part4
) 3>&1 #part3
) | (read xs; exit $xs) #part2
) 4>&1 #part1
নীচে থেকে:
#part3
) এবং ডান ( #part2
) কমান্ডগুলি কার্যকর করা হয়। exit $xs
পাইপের শেষ কমান্ডও এবং এর অর্থ হল স্টিডিনের স্ট্রিংটি সম্পূর্ণ নির্মাণের প্রস্থান স্থিতি হবে।#part2
পুরো নির্মাণের প্রস্থান স্থিতি হবে status#part5
এবং #part6
) এবং ডান ( filter >&4
) কমান্ডগুলি কার্যকর করা হয়। এর বর্ণনা আউটপুটটি filter
ডেস্ক্রিপ্টর 4 ফাইলের দিকে পুনঃনির্দেশিত করা #part1
হয়। ফাইল বিবরণীতে 4 স্ট্যাডআউটে পুনর্নির্দেশ করা হয়েছিল। এর অর্থ filter
হ'ল আউটপুট হ'ল সম্পূর্ণ নির্মাণের স্টাডআউট d#part6
ফাইল বর্ণনাকারী 3 এ মুদ্রিত হয় #part3
ফাইল বিবরণীতে 3 এ পুনঃনির্দেশিত হয়েছিল #part2
। এর অর্থ এই যে প্রস্থানের স্থিতিটি #part6
সম্পূর্ণ নির্মাণের জন্য চূড়ান্ত প্রস্থান স্থিতি হবে।someprog
মৃত্যুদন্ড কার্যকর করা হয় প্রস্থান স্থিতি নেওয়া হয় #part5
। স্টাডাউটটি পাইপটি দ্বারা takenোকানো হয় #part4
এবং এতে ফরোয়ার্ড করা হয় filter
। উল্লিখিত হিসাবে আউটপুট filter
পরিবর্তে stdout পৌঁছাবে#part4
(read; exit $REPLY)
(exec 3>&- 4>&-; someprog)
থেকে সহজসাধ্য someprog 3>&- 4>&-
।
{ { { { someprog 3>&- 4>&-; echo $? >&3; } | filter >&4; } 3>&1; } | { read xs; exit $xs; }; } 4>&1
আপনি যা চেয়েছিলেন ঠিক তেমন না হলেও আপনি ব্যবহার করতে পারেন
#!/bin/bash -o pipefail
যাতে আপনার পাইপগুলি সর্বশেষ নন শূন্য ফেরত দেয়।
কিছুটা কম কোডিং হতে পারে
সম্পাদনা: উদাহরণ
[root@localhost ~]# false | true
[root@localhost ~]# echo $?
0
[root@localhost ~]# set -o pipefail
[root@localhost ~]# false | true
[root@localhost ~]# echo $?
1
set -o pipefail
স্ক্রিপ্টের অভ্যন্তরে আরও দৃ be় হওয়া উচিত, উদাহরণস্বরূপ, কেউ যদি স্ক্রিপ্টের মাধ্যমে কার্যকর করে bash foo.sh
।
-o pipefail
পসিক্সে নেই।
#!/bin/bash -o pipefail
। ত্রুটি:/bin/bash: line 0: /bin/bash: /tmp/ff: invalid option name
#!
প্রথমটি পরলোক লাইন, এবং তাই এই হয়ে /bin/bash
-o pipefail
/tmp/ff
প্রয়োজনীয় পরিবর্তে /bin/bash
-o
pipefail
/tmp/ff
- getopt
ব্যবহার (বা অনুরূপ) পার্সিং optarg
, যা পরবর্তী আইটেম ARGV
, আর্গুমেন্ট হিসাবে যাও -o
, যাতে এটি ব্যর্থ হয়। আপনি যদি একটি মোড়কের (বলুন করতে, হলে bash-pf
যে শুধু করেনি exec /bin/bash -o pipefail "$@"
, এবং যে করা #!
লাইন, যে কাজ করবে আরো দেখুন:। En.wikipedia.org/wiki/Shebang_%28Unix%29
সম্ভব হলে আমি যা করি তা হ'ল বাইরে থেকে প্রস্থান কোডটি ফিড foo
করা bar
। উদাহরণস্বরূপ, যদি আমি জানি যে foo
কখনই কেবল অঙ্কের সাথে কোনও লাইন তৈরি করে না, তবে আমি কেবলমাত্র প্রস্থান কোডটি মোকাবেলা করতে পারি:
{ foo; echo "$?"; } | awk '!/[^0-9]/ {exit($0)} {…}'
বা যদি আমি জানি যে আউটপুটটিতে foo
কখনও ন্যায়বিচারের সাথে একটি লাইন থাকে না .
:
{ foo; echo .; echo "$?"; } | awk '/^\.$/ {getline; exit($0)} {…}'
এটি সর্বদা করা যেতে পারে যদি bar
শেষ লাইন ব্যতীত অন্য সকলের সাথে কাজ করার কোনও উপায় থাকে এবং শেষ লাইনে এর প্রস্থান কোড হিসাবে চলে যায়।
যদি bar
কোনও জটিল পাইপলাইন যার আউটপুট আপনার প্রয়োজন হয় না, আপনি আলাদা ফাইল বিবরণীতে প্রস্থান কোড প্রিন্ট করে এর অংশটি বাইপাস করতে পারেন।
exit_codes=$({ { foo; echo foo:"$?" >&3; } |
{ bar >/dev/null; echo bar:"$?" >&3; }
} 3>&1)
এরপর $exit_codes
সাধারণত foo:X bar:Y
, কিন্তু এটা হতে পারে bar:Y foo:X
যদি bar
তার ইনপুট সব পড়ার আগে বা যদি অপয়া করছি শোধবোধ। আমি মনে করি 512 বাইট অবধি পাইপগুলিতে লেখা সমস্ত ইউনিসগুলিতে পারমাণবিক, সুতরাং যতক্ষণ না ট্যাগ স্ট্রিং 507 বাইটের নিচে থাকে ততক্ষণ foo:$?
এবং bar:$?
অংশগুলি সংমিশ্রিত হবে না।
আপনার যদি আউটপুট ক্যাপচার করতে হয় তবে bar
এটি কঠিন হয়ে পড়ে। আপনি bar
কখনই কোনও লাইন ধারণ করবেন না যা বহির্গমন কোড ইঙ্গিতের মতো দেখায় না তার আউটপুট সাজিয়ে আপনি উপরের কৌশলগুলিকে একত্রিত করতে পারেন তবে এটি খুব কমই যায়।
output=$(echo;
{ { foo; echo foo:"$?" >&3; } |
{ bar | sed 's/^/^/'; echo bar:"$?" >&3; }
} 3>&1)
nl='
'
foo_exit_code=${output#*${nl}foo:}; foo_exit_code=${foo_exit_code%%$nl*}
bar_exit_code=${output#*${nl}bar:}; bar_exit_code=${bar_exit_code%%$nl*}
output=$(printf %s "$output" | sed -n 's/^\^//p')
এবং, অবশ্যই, স্থিতি সংরক্ষণের জন্য একটি অস্থায়ী ফাইল ব্যবহার করার সহজ বিকল্প রয়েছে । সরল, কিন্তু না যে উৎপাদনে সহজ:
/tmp
একমাত্র জায়গা যেখানে স্ক্রিপ্ট ফাইলগুলি লিখতে সক্ষম হবে তা নিশ্চিত। ব্যবহার করুন mktemp
, যা পসিক্স নয় তবে আজকাল সমস্ত গুরুতর সংযোগগুলিতে উপলভ্য।foo_ret_file=$(mktemp -t)
{ foo; echo "$?" >"$foo_ret_file"; } | bar
bar_ret=$?
foo_ret=$(cat "$foo_ret_file"; rm -f "$foo_ret_file")
পাইপলাইন থেকে শুরু:
foo | bar | baz
কেবলমাত্র পসিক্স শেল এবং অস্থায়ী ফাইল ব্যবহার করে এখানে একটি সাধারণ সমাধান রয়েছে:
exec 4>&1
error_statuses="`((foo || echo "0:$?" >&3) |
(bar || echo "1:$?" >&3) |
(baz || echo "2:$?" >&3)) 3>&1 >&4`"
exec 4>&-
$error_statuses
প্রতিটি কমান্ডটি কোন আদেশকে নির্গত করে তা নির্ধারণের জন্য সূচি সহ কোনও ব্যর্থ প্রক্রিয়ার স্থিতি কোড রয়েছে।
# if "bar" failed, output its status:
echo "$error_statuses" | grep '1:' | cut -d: -f2
# test if all commands succeeded:
test -z "$error_statuses"
# test if the last command succeeded:
! echo "$error_statuses" | grep '2:' >/dev/null
$error_statuses
আমার পরীক্ষাগুলির চারপাশে উদ্ধৃতিগুলি নোট করুন ; তাদের ছাড়া grep
পার্থক্য করতে পারে না কারণ নিউলাইনগুলি ফাঁকা জায়গায় জোর করে।
সুতরাং আমি লেসমানার মতো একটি উত্তর অবদান রাখতে চেয়েছিলাম, তবে আমি মনে করি আমার সম্ভবত কিছুটা সহজ এবং কিছুটা সুবিধাজনক খাঁটি-বোর্ন শেল সমাধান:
# You want to pipe command1 through command2:
exec 4>&1
exitstatus=`{ { command1; printf $? 1>&3; } | command2 1>&4; } 3>&1`
# $exitstatus now has command1's exit status.
আমি মনে করি এটি ভিতরে থেকে সর্বোত্তমভাবে ব্যাখ্যা করা হয়েছে - কমান্ড 1 তার নিয়মিত আউটপুটটি স্টাডআউট (ফাইল বর্ণনাকারী 1) এ কার্যকর করবে এবং মুদ্রণ করবে, তারপরে এটি শেষ হয়ে গেলে, প্রিন্টফ তার স্টাডাউটে কমান্ড 1 এর প্রস্থান কোডটি কার্যকর করবে এবং প্রিন্ট করবে, কিন্তু সেই স্টাডআউটটি পুনঃনির্দেশিত হবে ফাইল বর্ণনাকারী 3।
কমান্ড 1 চলমান থাকাকালীন, এর স্টডআউটটি কমান্ড 2 এ পাইপ করা হচ্ছে (প্রিন্টফের আউটপুট কখনই এটি কমান্ড 2 এ পরিণত হয় না কারণ আমরা এটি 1 এর পরিবর্তে 3 ফাইল-ডেস্ক্রিপ্টারে প্রেরণ করি, যা পাইপটি পড়ে)। তারপরে আমরা কমান্ড 2 এর আউটপুটটিকে ফাইল বর্ণনাকারী 4 এ পুনঃনির্দেশ করি, যাতে এটি ফাইল বর্ণনাকারী 1 এর বাইরেও থাকে - কারণ আমরা ফাইল বর্ননকারীকে কিছুটা পরে ফ্রি চাই, কারণ আমরা ফাইল বিবরণীতে প্রিন্টফ আউটপুট 3 ফিরিয়ে আনব ফাইল ডেস্ক্রিপ্টারে 1 - কারণ এটি হ'ল কমান্ড সাবস্টিটিউশন (ব্যাকটিক্স) ক্যাপচার করবে এবং এটি ভেরিয়েবলের মধ্যে স্থাপন করবে।
ম্যাজিকের চূড়ান্ত বিটটি হ'ল প্রথমটি exec 4>&1
আমরা পৃথক কমান্ড হিসাবে করি - এটি বাহ্যিক শেলের স্টডআউটটির অনুলিপি হিসাবে ফাইল বর্ণনাকারী 4 খুলবে। কমান্ড প্রতিস্থাপন স্ট্যান্ডার্ডে যা লেখা আছে তার ভিতরে থাকা কমান্ডের দৃষ্টিকোণ থেকে তা ক্যাপচার করবে - তবে, যেহেতু কমান্ড 2 এর আউটপুট বর্ণনাকারী 4 ফাইল করবে, কমান্ড প্রতিস্থাপনের ক্ষেত্রে কমান্ড প্রতিস্থাপন এটি ক্যাপচার করে না - তবে, একবার কমান্ড প্রতিস্থাপনের "আউট" হয়ে গেলে, এটি কার্যকরভাবে এখনও স্ক্রিপ্টের সামগ্রিক ফাইল বর্ণনাকারী 1 এ যায়।
( exec 4>&1
এটি একটি পৃথক কমান্ড হতে হবে কারণ আপনি যখন কমান্ড সাবস্টিটিউশনের অভ্যন্তরে কোনও ফাইল বর্ণনাকারীর কাছে লেখার চেষ্টা করেন তখন প্রচলিত শেলগুলি এটি পছন্দ করে না, এটি "বহিরাগত" কমান্ডে খোলা হয় যা প্রতিস্থাপনটি ব্যবহার করছে। তাই এটি হ'ল এটি করার সহজতম পোর্টেবল উপায়))
আপনি এটিকে কম প্রযুক্তিগত এবং আরও কৌতুকপূর্ণ উপায়ে দেখতে পারেন, যেন কমান্ডের আউটপুটগুলি একে অপরকে লাফিয়ে ফেলা হয়: কমান্ড 1-তে কমান্ড 1 পাইপস, তারপরে প্রিন্টফের আউটপুট কমান্ড 2-এর উপরে লাফ দেয় যাতে কমান্ড 2 এটি ধরা না দেয় এবং তারপরে কমান্ড 2 এর আউটপুট কমান্ড প্রতিস্থাপনের বাইরে ছড়িয়ে পড়ে ঠিক একই সময়ে প্রিন্টফ স্থির করে নিতে পারে যাতে এটি ভেরিয়েবলের মধ্যে শেষ হয়, এবং কমান্ড 2 এর আউটপুটটি তার আনন্দের পথে স্ট্যান্ডার্ড আউটপুটে লেখা হয়, ঠিক যেমন একটি সাধারণ পাইপে
এছাড়াও, যেমনটি আমি এটি বুঝতে পেরেছি, $?
পাইপটিতে এখনও দ্বিতীয় কমান্ডের রিটার্ন কোড থাকবে, কারণ পরিবর্তনশীল কার্যভার, কমান্ডের বিকল্প এবং যৌগিক কমান্ডগুলি তাদের অভ্যন্তরের কমান্ডের রিটার্ন কোডের জন্য কার্যকরভাবে স্বচ্ছ, সুতরাং এর রিটার্নের স্থিতি কমান্ড 2 এর প্রচার করা উচিত - এটি এবং অতিরিক্ত ক্রিয়াকলাপটি সংজ্ঞায়িত না করাই আমি কেন লেসমানার প্রস্তাবিত চেয়ে কিছুটা ভাল সমাধান হতে পারে বলে আমি মনে করি।
ক্যাভিয়েটস লেসমানার উল্লেখ অনুসারে, সম্ভবত কমান্ড 1 ফাইল বর্ণনাকারী 3 বা 4 ব্যবহার করে শেষ হবে, যাতে আরও দৃ rob় হয়, আপনি এটি করতে পারেন:
exec 4>&1
exitstatus=`{ { command1 3>&-; printf $? 1>&3; } 4>&- | command2 1>&4; } 3>&1`
exec 4>&-
মনে রাখবেন যে আমি আমার উদাহরণে যৌগিক আদেশগুলি ব্যবহার করি তবে সাবশেলগুলি (এর ( )
পরিবর্তে ব্যবহার { }
করাও কার্যকর হবে, যদিও এটি সম্ভবত কম দক্ষ হতে পারে))
কমান্ডগুলি ফাইল প্রবর্তনকারী প্রক্রিয়া থেকে ফাইল বর্ণনাকারীদের উত্তরাধিকার সূত্রে প্রাপ্ত হয়, সুতরাং সম্পূর্ণ দ্বিতীয় লাইনে ফাইল বর্ণনাকারী চারটি উত্তরাধিকার সূত্রে প্রাপ্ত হয় এবং এরপরে যৌগিক কমান্ডটি 3>&1
ফাইল বর্ণনাকারী তিনটি উত্তরাধিকার সূত্রে প্রাপ্ত হয়। সুতরাং এটি 4>&-
নিশ্চিত করে যে অভ্যন্তরীণ যৌগ কমান্ডটি ফাইল বর্ণনাকারী চারটি 3>&-
উত্তরাধিকার সূত্রে প্রাপ্ত হবে না এবং তিনটি ফাইল বর্ণনাকারীর অধিকারী হবে না, সুতরাং কমান্ড 1 একটি 'ক্লিনার', আরও মানক পরিবেশ পায়। আপনি অভ্যন্তরের 4>&-
পাশের পাশেও সরে যেতে পারতেন 3>&-
তবে আমি বুঝতে পারি কেন কেবল তার সুযোগটি যতটা সম্ভব সীমাবদ্ধ করা যায় না।
আমি নিশ্চিত নই যে জিনিসগুলি প্রায়শই ফাইল বর্ণনাকারী তিন এবং চারটি সরাসরি কীভাবে ব্যবহার করে - আমি মনে করি বেশিরভাগ প্রোগ্রাম প্রোগ্রাম-এ-মুহুর্তে ফাইল বর্ণনাকারী-না-ব্যবহার করা সিস্কলগুলি ব্যবহার করে তবে কখনও কখনও কোড ডেস্ক্রিপ্ট 3 ফাইল সরাসরি লিখে দেয়, আমি অনুমান করুন (কোনও ফাইল ফাইল বিবরণকারী খালি আছে কিনা তা দেখার জন্য, এবং এটি যদি ব্যবহার করা হয় বা এটি না হয় তবে সে অনুযায়ী অন্যরকম আচরণ করে তা দেখার জন্য আমি কোনও কল্পনা করতে পারি)। সুতরাং পরে সম্ভবত মনে রাখা এবং সাধারণ উদ্দেশ্য ক্ষেত্রে জন্য ব্যবহার করা ভাল।
-bash: 3: Bad file descriptor
।
আপনার যদি আরও ব্যবহার্য প্যাকেজ ইনস্টল করা থাকে তবে আপনি মিসপাইপ ইউটিলিটিটি ব্যবহার করতে পারবেন যা আপনি যা বলেছেন ঠিক তেমন করে।
উপরের লেসমানার সমাধানটি নেস্টেড সাবপ্রসেসেসগুলি ব্যবহার { .. }
না করে ব্যবহারের পরিবর্তে ওভারহেড ছাড়াও করা যেতে পারে (মনে রাখবেন যে গ্রুপযুক্ত কমান্ডগুলির এই ফর্মটি সর্বদা সেমিকোলন দিয়ে শেষ করতে হবে)। এটার মতো কিছু:
{ { { { someprog; echo $? >&3; } | filter >&4; } 3>&1; } | stdintoexitstatus; } 4>&1
আমি এই নির্মাণটি ড্যাশ সংস্করণ ০.০.৫ এবং ব্যাশ সংস্করণ ৩.২.২৫ এবং ৪.২.৪২ সহ পরীক্ষা করেছি, সুতরাং কিছু শেল গোষ্ঠীকরণকে সমর্থন না { .. }
করলেও এটি পসিক্স অনুগত।
set -o pipefail
ksh বা কোনও সংখ্যক ছিটিয়ে wait
কমান্ড দিয়েও । আমি মনে করি এটি কমপক্ষে, ksh এর জন্য পার্সিং ইস্যু হতে পারে, যদি আমি সাবশেলগুলি ব্যবহার করতে আটকে থাকি তবে এটি ঠিক কাজ করে, তবে if
কেএসএসের জন্য সাব-শেল বৈকল্পিক বেছে নিতে অন্যের জন্য যৌগিক আদেশগুলি ছেড়ে দেয়, এটি ব্যর্থ হয় ।
এটি পোর্টেবল, অর্থাত্ কোনও পসিক্স কমপ্লায়েন্ট শেল নিয়ে কাজ করে, বর্তমান ডিরেক্টরিটি লেখার প্রয়োজন হয় না এবং একই কৌশল ব্যবহার করে একাধিক স্ক্রিপ্টগুলি একই সাথে চালানোর অনুমতি দেয়।
(foo;echo $?>/tmp/_$$)|(bar;exit $(cat /tmp/_$$;rm /tmp/_$$))
সম্পাদনা করুন: গিলসের মন্তব্যের পরে এখানে একটি শক্তিশালী সংস্করণ রয়েছে:
(s=/tmp/.$$_$RANDOM;((foo;echo $?>$s)|(bar)); exit $(cat $s;rm $s))
সম্পাদনা 2: এবং এখানে সন্দেহভাজন জিম মন্তব্যের পরে কিছুটা হালকা বৈকল্পিক:
(s=/tmp/.$$_$RANDOM;{foo;echo $?>$s;}|bar; exit $(cat $s;rm $s))
(s=/tmp/.$$_$RANDOM;{foo;echo $?>$s;}|bar; exit $(cat $s;rm $s))
। @ জোহান: আমি সম্মত যে বাশের সাথে এটি আরও সহজ তবে কিছু প্রসঙ্গে, কীভাবে বাশকে এড়ানো যায় তা জেনে রাখা উপযুক্ত।
নিম্নলিখিতটি @ পেট্রিকের উত্তরের সংযোজন হিসাবে বোঝানো হয়েছে, যদি আপনি সাধারণ সমাধানগুলির মধ্যে একটিও ব্যবহার করতে সক্ষম না হন।
এই উত্তরটি নিম্নলিখিতটি ধরে নিয়েছে:
$PIPESTATUS
নাset -o pipefail
অতিরিক্ত অনুমান। আপনি সমস্ত থেকে মুক্তি পেতে পারেন, তবে এই ক্লোবারগুলি রেসিপিটি খুব বেশি, তাই এটি এখানে আচ্ছাদিত নয়:
- আপনি যা জানতে চান তা হ'ল পিআইপিইতে সমস্ত কমান্ডের প্রস্থান কোড 0 রয়েছে।
- আপনার অতিরিক্ত সাইড ব্যান্ডের তথ্য লাগবে না।
- আপনার শেল সমস্ত পাইপ কমান্ড ফিরে আসার অপেক্ষা করে না।
পূর্বে: foo | bar | baz
তবে এটি কেবল সর্বশেষ কমান্ডের প্রস্থান কোড ( baz
) প্রদান করে
চেয়েছিল: পাইপের কোনও কমান্ড ব্যর্থ হলে $?
অবশ্যই 0
(সত্য) হওয়া উচিত নয়
পরে:
TMPRESULTS="`mktemp`"
{
rm -f "$TMPRESULTS"
{ foo || echo $? >&9; } |
{ bar || echo $? >&9; } |
{ baz || echo $? >&9; }
#wait
! read TMPRESULTS <&8
} 9>>"$TMPRESULTS" 8<"$TMPRESULTS"
# $? now is 0 only if all commands had exit code 0
ব্যাখ্যা:
mktemp
। এটি সাধারণত তত্ক্ষণাত্ একটি ফাইল তৈরি করে/tmp
wait
কার্যকলাপের জন্য দরকারি ksh
, কারণ ksh
সব নল শেষ কমান্ড জন্য অন্য অপেক্ষা করে না। তবে দয়া করে মনে রাখবেন যে কিছু পটভূমি কাজ উপস্থিত থাকলে অযাচিত পার্শ্ব প্রতিক্রিয়া রয়েছে, তাই আমি এটি ডিফল্টরূপে মন্তব্য করেছি। অপেক্ষাটি যদি ক্ষতি না করে তবে আপনি এটিতে মন্তব্য করতে পারেন।read
ফিরে আসে false
, সুতরাং true
একটি ত্রুটি নির্দেশ করেএটি একটি একক কমান্ডের জন্য প্লাগইন প্রতিস্থাপন হিসাবে ব্যবহার করা যেতে পারে এবং কেবল নিম্নলিখিতগুলির প্রয়োজন:
/proc/fd/N
বাগ:
এই স্ক্রিপ্টের /tmp
জায়গাগুলি ফুরিয়ে যাওয়ার ক্ষেত্রে একটি বাগ রয়েছে । আপনি এই কৃত্রিম ক্ষেত্রে বিরুদ্ধে সুরক্ষা প্রয়োজন হয়, তাহলে খুব, আপনি এটি নিম্নরূপ কি করতে পারেন, তবে এই অসুবিধা আছে, যে সংখ্যা 0
মধ্যে 000
পাইপে কমান্ড সংখ্যার উপর নির্ভর করে, তাই এটি সামান্য বেশি জটিল:
TMPRESULTS="`mktemp`"
{
rm -f "$TMPRESULTS"
{ foo; printf "%1s" "$?" >&9; } |
{ bar; printf "%1s" "$?" >&9; } |
{ baz; printf "%1s" "$?" >&9; }
#wait
read TMPRESULTS <&8
[ 000 = "$TMPRESULTS" ]
} 9>>"$TMPRESULTS" 8<"$TMPRESULTS"
বহনযোগ্যতা নোট:
ksh
এবং অনুরূপ শেলগুলি যা কেবলমাত্র শেষ পাইপ কমান্ডের জন্য অপেক্ষা করে তাদের wait
নিরক্ষিত প্রয়োজন
শেষ উদাহরণটি printf "%1s" "$?"
পরিবর্তে ব্যবহার করে echo -n "$?"
কারণ এটি আরও বহনযোগ্য। প্রতিটি প্ল্যাটফর্ম -n
সঠিকভাবে ব্যাখ্যা করে না।
printf "$?"
এটিও করত, তবে printf "%1s"
কিছু সত্যিকারের ভাঙা প্ল্যাটফর্মে স্ক্রিপ্ট চালানোর ক্ষেত্রে কিছু কোণার কেস ধরা পড়ে। (পড়ুন: আপনি প্রোগ্রামে ঘটলে paranoia_mode=extreme
।)
প্লাটফর্মগুলিতে এফডি 8 এবং এফডি 9 উচ্চতর হতে পারে যা একাধিক সংখ্যা সমর্থন করে। একটি পসিক্স কনফরম্যান্ট শেলটি AFAIR কেবলমাত্র একক সংখ্যা সমর্থন করার প্রয়োজন নেই।
ডেবিয়ান 8.2 সাথে পরীক্ষিত হয়েছিল sh
, bash
, ksh
, ash
, sash
এবং এমনকিcsh
কিছুটা সতর্কতা সহ, এটি কাজ করা উচিত:
foo-status=$(mktemp -t)
(foo; echo $? >$foo-status) | bar
foo_status=$(cat $foo-status)
নিম্নলিখিত 'if' ব্লক কেবল 'কমান্ড' সফল হলে চলবে:
if command; then
# ...
fi
বিশেষভাবে বলতে গেলে, আপনি এই জাতীয় কিছু চালাতে পারেন:
haconf_out=/path/to/some/temporary/file
if haconf -makerw > "$haconf_out" 2>&1; then
grep -iq "Cluster already writable" "$haconf_out"
# ...
fi
যা haconf -makerw
এটির স্টডআউট এবং স্টডারকে "$ haconf_out" এ চালাবে এবং সংরক্ষণ করবে । যদি থেকে প্রাপ্ত মানটি haconf
সত্য হয়, তবে 'যদি' ব্লকটি কার্যকর করা grep
হবে এবং "ক্লাস্টার ইতিমধ্যে লিখনযোগ্য" এর বিপরীতে এটি মিলানোর চেষ্টা করে "$ হ্যাকনফ_আউট" পড়বে।
লক্ষ্য করুন পাইপগুলি স্বয়ংক্রিয়ভাবে নিজেকে পরিষ্কার করে; পুনঃনির্দেশের সাহায্যে আপনার কাজ শেষ হয়ে গেলে "$ haconf_out" মুছে ফেলার জন্য যত্নবান হতে হবে।
এর মতো মার্জিত নয় pipefail
, তবে বৈধ বিকল্প যদি এই কার্যকারিতাটি নাগালের মধ্যে না থাকে।
Alternate example for @lesmana solution, possibly simplified.
Provides logging to file if desired.
=====
$ cat z.sh
TEE="cat"
#TEE="tee z.log"
#TEE="tee -a z.log"
exec 8>&- 9>&-
{
{
{
{ #BEGIN - add code below this line and before #END
./zz.sh
echo ${?} 1>&8 # use exactly 1x prior to #END
#END
} 2>&1 | ${TEE} 1>&9
} 8>&1
} | exit $(read; printf "${REPLY}")
} 9>&1
exit ${?}
$ cat zz.sh
echo "my script code..."
exit 42
$ ./z.sh; echo "status=${?}"
my script code...
status=42
$
(কমপক্ষে বাশ সহ) একত্রিত হয়ে set -e
সুস্পষ্টভাবে পাইপফিল অনুকরণ করতে পাইপ ত্রুটি থেকে প্রস্থান করতে সাবশেল ব্যবহার করতে পারেন
set -e
foo | bar
( exit ${PIPESTATUS[0]} )
rest of program
সুতরাং যদি foo
কোনও কারণে ব্যর্থ হয় - বাকি প্রোগ্রামটি কার্যকর করা হবে না এবং স্ক্রিপ্টটি সংশ্লিষ্ট ত্রুটি কোড সহ প্রস্থান করবে। (এটি ধরে নিয়েছে যে foo
এটির নিজস্ব ত্রুটিটি মুদ্রণ করে, যা ব্যর্থতার কারণটি বোঝার জন্য যথেষ্ট)
সম্পাদনা : এই উত্তরটি ভুল, তবে আকর্ষণীয়, তাই আমি এটি ভবিষ্যতের রেফারেন্সের জন্য রেখে দেব।
!
কমান্ডটিতে
একটি যুক্ত করা রিটার্ন কোডকে উল্টে দেয়।
http://tldp.org/LDP/abs/html/exit-status.html
# =========================================================== #
# Preceding a _pipe_ with ! inverts the exit status returned.
ls | bogus_command # bash: bogus_command: command not found
echo $? # 127
! ls | bogus_command # bash: bogus_command: command not found
echo $? # 0
# Note that the ! does not change the execution of the pipe.
# Only the exit status changes.
# =========================================================== #
ls
, এর প্রস্থান কোডটি bogus_command