මට ක්රියාවලි දෙකක් ඇති foo
අතර bar
, නලයකට සම්බන්ධ කර ඇත:
$ foo | bar
bar
සෑම විටම 0 පිටවෙයි; මම පිටවීමේ කේතය ගැන උනන්දු වෙමි foo
. එය ලබා ගැනීමට ක්රමයක් තිබේද?
මට ක්රියාවලි දෙකක් ඇති foo
අතර bar
, නලයකට සම්බන්ධ කර ඇත:
$ foo | bar
bar
සෑම විටම 0 පිටවෙයි; මම පිටවීමේ කේතය ගැන උනන්දු වෙමි foo
. එය ලබා ගැනීමට ක්රමයක් තිබේද?
Answers:
ඔබ භාවිතා කරන්නේ නම් , නල මාර්ගයේ එක් එක් මූලද්රව්යයේ පිටවීමේ තත්ත්වය ලබා ගැනීමට 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
in zsh
) නමින් අරාව විචල්යයක් Bash සතුව ඇත .
$ true | true; echo "${PIPESTATUS[@]}"
0 0
$ false | true; echo "${PIPESTATUS[@]}"
1 0
$ false | true; echo "${PIPESTATUS[0]}"
1
$ true | false; echo "${PIPESTATUS[@]}"
0 1
ඔබට අවශ්ය නල මාර්ගයේ නිශ්චිත අගය ලබා ගැනීමට ඔබට 3 වන විධාන උදාහරණය භාවිතා කළ හැකිය.
මෙය විසඳුම්වල වඩාත්ම නොසැලකිලිමත්කමයි. සෑම විධානයක්ම වෙන වෙනම ධාවනය කර තත්වය අල්ලා ගන්න
$ 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
මෙම ඉදිකිරීමේ ප්රති result ලය ඉදිකිරීම් වල stdout filter
ලෙසත්, පිටවීමේ තත්වයෙන් ඉදිකිරීම් වල පිටවීමේ තත්වය someprog
ලෙසත් වේ.
මෙම ඉදිකිරීම උප-ෂෙල් {...}
වෙනුවට සරල විධාන කණ්ඩායම්කරණය සමඟ ද ක්රියා කරයි (...)
. subhells හි යම් ඇඟවුම් ඇති අතර අනෙක් ඒවා අතර කාර්ය සාධන පිරිවැයක් ඇත. වැඩි විස්තර සඳහා සියුම් බාෂ් අත්පොත කියවන්න: 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
අවාසනාවට, ව්යාකරණ ව්යාකරණ සඳහා වක්ර වරහන් සඳහා අවකාශ සහ අර්ධ සළකුණු අවශ්ය වන අතර එමඟින් ඉදිකිරීම් වඩාත් ඉඩකඩ සහිත වේ.
මෙම පා text යේ ඉතිරි කොටස සඳහා මම උපසෙල් ප්රභේදය භාවිතා කරමි.
උදාහරණය 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 උරුම වේ. ගොනු විස්තර 3 someprog
වෙත ලියන්නේ නම් එය පිටවීමේ තත්වය බවට පත්වේ. 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
ක්රියාත්මක පෙර ගොනුව descriptor වැසුනු 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
පයිප්පයේ අවසාන විධානය ද වන අතර එයින් අදහස් කරන්නේ stdin වෙතින් වන නූල සමස්ත ඉදිකිරීමේ පිටවීමේ තත්වය වනු ඇති බවයි.#part2
අතර අනෙක් අතට එය සම්පූර්ණ ඉදිකිරීම් වල පිටවීමේ තත්වය වනු ඇති බවයි.#part5
සහ #part6
) සහ දකුණේ ( filter >&4
) විධාන ක්රියාත්මක වේ. ප්රතිදානය filter
ගොනු විස්තර #part1
කරන්නා 4 වෙත හරවා යවනු ලැබේ. ගොනු විස්තරය 4 හි stdout වෙත හරවා යවන ලදි. මෙයින් අදහස් කරන්නේ ප්රතිදානය filter
යනු සමස්ත ඉදිකිරීම් වලම ස්ථායීතාවය බවයි.#part6
ගොනු විස්තර කරන්නා 3 වෙත මුද්රණය කර ඇත. #part3
ගොනු විස්තරයේ 3 වෙත හරවා යවන ලදි #part2
. මෙයින් අදහස් කරන්නේ පිටවීමේ තත්වය #part6
සමස්ත ඉදිකිරීම් සඳහා අවසාන පිටවීමේ තත්වය වනු ඇති බවයි.someprog
ක්රියාත්මක වේ. පිටවීමේ තත්වය ගනු ලැබේ #part5
. Stdout පයිප්පයෙන් ගෙන #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
ස්ක්රිප්ට් එක තුළ වඩාත් ශක්තිමත් විය යුතුය, උදා bash foo.sh
.
-o pipefail
POSIX හි නොමැති බව සලකන්න .
#!/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 "$@"
#!
හැකි සෑම විටම මම කරන්නේ පිටවීමේ කේතය සිට පෝෂණය foo
කිරීමයි bar
. උදාහරණයක් ලෙස, foo
කිසි විටෙකත් ඉලක්කම් සහිත රේඛාවක් නිපදවන්නේ නැති බව මා දන්නේ නම්, මට පිටවීමේ කේතය සම්බන්ධ කර ගත හැකිය:
{ foo; echo "$?"; } | awk '!/[^0-9]/ {exit($0)} {…}'
නැතහොත් ප්රතිදානයෙන් foo
කිසි විටෙකත් සාධාරණ රේඛාවක් අඩංගු නොවන බව මා දන්නේ නම් .
:
{ foo; echo .; echo "$?"; } | awk '/^\.$/ {getline; exit($0)} {…}'
bar
අන්තිම පේළිය හැර අන් සියල්ලටම වැඩ කිරීමට ක්රමයක් තිබේ නම් මෙය සැමවිටම කළ හැකි අතර අවසාන පේළියේ පිටවීමේ කේතය ලෙස සම්මත කරන්න.
නම් bar
වෙනස් ගොනු descriptor මත පිටවීම් කේතය මුද්රණය විසින් සිය නිමැවුම් ඔබ ඔබ, ඔබට හැකි අවශ්ය නැහැ එය කොටසක් බයිපාස් සංකීර්ණ නල වේ.
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
POSIX shell පමණක් භාවිතා කරන සාමාන්ය විසඳුමක් මෙන්න තාවකාලික ලිපිගොනු:
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.
මම සිතන්නේ මෙය ඇතුළත සිට වඩාත් හොඳින් පැහැදිලි කර ඇති බවයි - command1 එහි නිත්ය ප්රතිදානය stdout (ගොනු විස්තර 1) මත ක්රියාත්මක කර මුද්රණය කරනු ඇත, පසුව එය අවසන් වූ පසු printf විසින් එහි stdout හි command1 හි පිටවීමේ කේතය ක්රියාත්මක කර මුද්රණය කරනු ඇත, නමුත් එම stdout වෙත හරවා යවනු ලැබේ. ගොනු විස්තර 3.
විධාන 1 ක්රියාත්මක වන අතර, එහි stdout විධාන 2 වෙත නල කරනු ලැබේ. ඉන්පසුව අපි විධාන 2 හි ප්රතිදානය ගොනු විස්තර 4 වෙත හරවා යවන අතර එමඟින් එය ගොනු විස්තර 1 න් බැහැරව පවතී - අපට ගොනු විස්තරය 1 ටික කලකට පසුව නොමිලේ අවශ්ය නිසා, අපි ගොනු විස්තර 3 හි printf ප්රතිදානය නැවත ගොනු විස්තරයට ගෙන එනු ඇත. 1 - එය විධාන ආදේශනය (බැක්ටික්ස්) ග්රහණය කර ගන්නා අතර එය විචල්යයට ඇතුළත් වේ.
මැජික් වල අවසාන කොටස නම් මුලින්ම exec 4>&1
අපි කළේ වෙනම විධානයක් ලෙසයි - එය බාහිර කවචයේ stdout හි පිටපතක් ලෙස ගොනු විස්තර 4 විවෘත කරයි. විධාන ආදේශනය එහි ඇති විධාන දෘෂ්ටි කෝණයෙන් සම්මතයෙන් ලියා ඇති ඕනෑම දෙයක් ග්රහණය කරගනු ඇත - නමුත්, විධාන ආදේශනය සම්බන්ධයෙන් විධාන 2 හි ප්රතිදානය විස්තර කරන්නා 4 ගොනු කිරීමට යන බැවින්, විධාන ආදේශනය එය ග්රහණය නොකරයි - කෙසේ වෙතත්, විධාන ආදේශනයෙන් එය "ඉවත්" වූ පසු, එය තවමත් ස්ක්රිප්ට්හි සමස්ත ගොනු විස්තර 1 වෙත යයි.
( exec 4>&1
මෙය වෙනම විධානයක් විය යුතුය, මන්ද ඔබ විධාන ආදේශකයක් තුළ ගොනු විස්තර කරන්නෙකුට ලිවීමට උත්සාහ කරන විට බොහෝ පොදු කවච එයට අකමැති වන අතර එය ආදේශකය භාවිතා කරන "බාහිර" විධානයෙන් විවෘත වේ. එබැවින් මෙය එය කළ හැකි සරලම අතේ ගෙන යා හැකි ක්රමය.)
ඔබට එය අඩු තාක්ෂණික හා සෙල්ලක්කාර ආකාරයකින් බැලීමට හැකිය, විධානවල ප්රතිදානයන් එකිනෙක පිම්මක් මෙන්: විධාන 1 පයිප්ප විධාන 2 වෙතට, එවිට printf හි ප්රතිදානය විධාන 2 හරහා පනින අතර එමගින් විධාන 2 එය අල්ලා නොගනී. විධාන 2 හි ප්රතිදානය විධාන ආදේශකයෙන් පිටතට හා පිටතට පනිනවා, ආදේශනය අල්ලා ගැනීමට නියමිත වේලාවට මුද්රණය වන විට එය විචල්යයෙන් අවසන් වන අතර විධාන 2 හි ප්රතිදානය සම්මත ප්රතිදානයට ලියා ඇති ආකාරයටම විනෝදජනක ලෙස ඉදිරියට යයි. සාමාන්ය පයිප්පයක.
එසේම, මා තේරුම් ගත් පරිදි, $?
පයිප්පයේ දෙවන විධානයේ ආපසු කේතය තවමත් අඩංගු වනු ඇත, මන්ද විචල්ය පැවරුම්, විධාන ආදේශක සහ සංයුක්ත විධාන සියල්ලම ඔවුන් තුළ ඇති විධානයේ ආපසු කේතයට විනිවිද පෙනෙන බැවින් නැවත පැමිණීමේ තත්වය command2 ප්රචාරය කළ යුතුය - මෙය, සහ අතිරේක ශ්රිතයක් නිර්වචනය නොකිරීම නිසා, මෙය ලෙස්මානා විසින් යෝජනා කරන ලද විසඳුමට වඩා තරමක් හොඳ විසඳුමක් විය හැකි යැයි මම සිතමි.
ලෙස්මානා සඳහන් කර ඇති පරිදි, විධාන 1 යම් අවස්ථාවක දී ගොනු විස්තර 3 හෝ 4 භාවිතා කිරීමට ඉඩ ඇත, එබැවින් වඩාත් ශක්තිමත් වීමට නම් ඔබ කරන්නේ:
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
මම මෙම ඉදිකිරීම ඩෑෂ් අනුවාදය 0.5.5 සහ බාෂ් අනුවාද 3.2.25 සහ 4.2.42 සමඟ පරීක්ෂා කර ඇත්තෙමි, එබැවින් සමහර ෂෙල් වෙඩි { .. }
කණ්ඩායම්කරණයට සහය නොදක්වුවද එය තවමත් පොසික්ස් අනුකූල වේ.
set -o pipefail
කිරීමට නොහැකි අතර , ksh වලින් හෝ ඉසින ලද wait
විධාන ගණනක් සමඟ වුවද. මම සිතන්නේ, එය අවම වශයෙන් ksh සඳහා විග්රහ කිරීමේ ගැටලුවක් විය හැකි අතර, මම උප-ෂෙල් භාවිතා කිරීමට ඇලී සිටිනවා සේම එය හොඳින් ක්රියාත්මක වේ, නමුත් if
ksh සඳහා උපසෙල් ප්රභේදය තෝරා ගැනීමට වුවද, අනෙක් අයට සංයුක්ත විධානයන් තබන්න, එය අසමත් වේ .
ඔබට පොදු විසඳුම් වලින් එකක් භාවිතා කිරීමට නොහැකි නම් පහත දැක්වෙන්නේ at පැට්රික්ගේ පිළිතුරට අතිරේකයක් ලෙස ය.
මෙම පිළිතුර පහත දැක්වේ:
$PIPESTATUS
හෝ නොදන්නා කවචයක් තිබේset -o pipefail
අතිරේක උපකල්පන. ඔබට සියල්ල ඉවත් කළ හැකිය, නමුත් මෙම වට්ටෝරුව ඕනෑවට වඩා වැඩි කරයි, එබැවින් එය මෙහි ආවරණය නොවේ:
- ඔබට දැන ගැනීමට අවශ්ය වන්නේ PIPE හි ඇති සියලුම විධානයන්ට පිටවීමේ කේතය 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
in 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
uncommented
පසුගිය උදාහරණයක් භාවිතා printf "%1s" "$?"
කරනවා වෙනුවට echo -n "$?"
මෙම වැඩි අතේ ගෙන යා හැකි නිසා. සෑම වේදිකාවක්ම -n
නිවැරදිව අර්ථ නිරූපණය නොකරයි .
printf "$?"
කෙසේ වෙතත් printf "%1s"
ඔබ එය ස්ක්රිප්ට් එක සැබවින්ම බිඳුණු වේදිකාවක ධාවනය කරන්නේ නම් සමහර කොනවල් අල්ලා ගනී. (කියවන්න: ඔබ වැඩසටහනට පිවිසෙන්නේ නම් paranoia_mode=extreme
.)
බහු ඉලක්කම් සඳහා සහාය වන වේදිකාවල FD 8 සහ FD 9 වැඩි විය හැකිය. AFAIR POSIX අනුකූලතා කවචයකට අවශ්ය වන්නේ තනි ඉලක්කම් සඳහා පමණි.
ඩේබියන් 8.2 සමග පරීක්ෂා කරන ලදී sh
, bash
, ksh
, ash
, sash
පවා හාcsh
මෙය අතේ ගෙන යා හැකි ය, එනම් ඕනෑම POSIX අනුකූල කවචයක් සමඟ ක්රියා කරයි, වත්මන් නාමාවලිය ලිවිය යුතු නොවන අතර එකම උපක්රමය භාවිතා කරමින් බහු ස්ක්රිප්ට එකවර ක්රියාත්මක වීමට ඉඩ දෙයි.
(foo;echo $?>/tmp/_$$)|(bar;exit $(cat /tmp/_$$;rm /tmp/_$$))
සංස්කරණය කරන්න: ගිලෙස්ගේ අදහස් දැක්වීමෙන් පසුව වඩා ශක්තිමත් අනුවාදයක් මෙන්න:
(s=/tmp/.$$_$RANDOM;((foo;echo $?>$s)|(bar)); exit $(cat $s;rm $s))
Edit2: සහ සැක සහිත ජිම් අදහස් දැක්වීමෙන් පසුව තරමක් සැහැල්ලු ප්රභේදයක් මෙහි ඇත:
(s=/tmp/.$$_$RANDOM;{foo;echo $?>$s;}|bar; exit $(cat $s;rm $s))
(s=/tmp/.$$_$RANDOM;{foo;echo $?>$s;}|bar; exit $(cat $s;rm $s))
. O ජොහාන්: බාෂ් සමඟ එය පහසු බව මම එකඟ වෙමි, නමුත් සමහර සන්දර්භය තුළ, බාෂ් වළක්වා ගන්නේ කෙසේදැයි දැන ගැනීම වටී.
ටිකක් පූර්වාරක්ෂාව සමඟ, මෙය ක්රියාත්මක විය යුතුය:
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
එමඟින් එහි stdout සහ stderr "$ haconf_out" වෙත ධාවනය කර ගබඩා කරනු ඇත . ආපසු ලබා දුන් අගය haconf
සත්ය නම්, 'if' කොටස ක්රියාත්මක වන අතර grep
"$ haconf_out" කියවනු ඇත, එය "දැනටමත් ලිවිය හැකි පොකුරට" ගැලපීමට උත්සාහ කරයි.
පයිප්ප ස්වයංක්රීයව පිරිසිදු වන බව සැලකිල්ලට ගන්න; නැවත හරවා යැවීම සමඟ "$ 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
$
(අවම වශයෙන් bash සමඟ) set -e
එක් අයෙකු සමඟ සංයෝජනය කිරීමෙන් නල දෝෂ පැහැදිලිව අනුකරණය කිරීමට සහ නල දෝෂයෙන් පිටවීමට උපසෙල් භාවිතා කළ හැකිය
set -e
foo | bar
( exit ${PIPESTATUS[0]} )
rest of program
එබැවින් foo
කිසියම් හේතුවක් නිසා අසමත් වුවහොත් - ඉතිරි වැඩසටහන ක්රියාත්මක නොවන අතර අනුරූප දෝෂ කේතය සමඟ ස්ක්රිප්ට් පිටවෙයි. (මෙය උපකල්පනය කරන්නේ foo
තමන්ගේම දෝෂයක් මුද්රණය කරන අතර එය අසාර්ථක වීමට හේතුව තේරුම් ගැනීමට ප්රමාණවත් වේ)
සංස්කරණය කරන්න : මෙම පිළිතුර වැරදියි, නමුත් සිත්ගන්නා සුළුය, එබැවින් මම එය අනාගත යොමු කිරීම සඳහා තබමි.
!
විධානයට
a එකතු කිරීමෙන් ආපසු කේතය ප්රතිලෝම වේ.
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
, නැති පිටවීම කේතය talk තෝරාගැනුම ප්රතිලෝම කරන්නbogus_command