Not: zshBuradaki örneklerin çoğu için "satır içi yorumları" kabul edecek şekilde yapılandırmazsanız ve yaptığım gibi bir proxy kabuğu aracılığıyla çalıştırmazsanız "kötü desenler" den şikayet eder sh <<-\CMD.
Tamam, yukarıdaki yorumlarda belirttiğim gibi, özellikle bashset -E hakkında bilmiyorum , ancak POSIX uyumlu kabukların bir değeri test etmek için basit bir yol sağladığını biliyorum:
sh -evx <<-\CMD
_test() { echo $( ${empty:?error string} ) &&\
echo "echo still works"
}
_test && echo "_test doesnt fail"
# END
CMD
sh: line 1: empty: error string
+ echo
+ echo 'echo still works'
echo still works
+ echo '_test doesnt fail'
_test doesnt fail
Eğer kullandığım olsa göreceksiniz Üstü parameter expansiontest etmek ${empty?} _test()hala returns sonuncu evinced gibi - bir pas echoBu başarısız değer öldürür çünkü oluşur $( command substitution )- onu içeren altkabuk, ancak üst kabuk _testşu anda - Kamyon tutar. Ve echoumursamıyor - 's bol mutlu bir tek hizmet etmek \newline; echoolduğunu değil bir test.
Ancak şunu düşünün:
sh -evx <<-\CMD
_test() { echo $( ${empty:?error string} ) &&\
echo "echo still works" ; } 2<<-INIT
${empty?function doesnt run}
INIT
_test ||\
echo "this doesnt even print"
# END
CMD
_test+ sh: line 1: empty: function doesnt run
_test()'sÖnceden değerlendirilmiş bir parametreyle girdiyi beslediğim için, INIT here-documentşimdi _test()işlev hiç çalışmaya çalışmaz. Dahası, shkabuk görünüşe göre hayaleti tamamen bırakıyor ve echo "this doesnt even print" hatta yazdırmıyor.
Muhtemelen istediğin bu değil .
Bunun nedeni ${var?}tarzı parametre genişleme olduğunu çıkmak üzere tasarlanmışshell bir eksik parametre durumunda bunun, bu gibi çalışır :
${parameter:?[word]}
Eğer Hata gösterir Nullveya Unset.parametre ayarlanmadan ya da boşsa, expansion of wordolacaktır (bu işaret eder ya da bir mesajı kelimesi atlanırsa ayarlanmadan) written to standard errorve shell exits with a non-zero exit status. Aksi takdirde, değeri parameter shall be substituted. Etkileşimli bir kabuktan çıkmak gerekmez.
Tüm belgeyi kopyalamayacağım / yapıştırmayacağım, ancak bir set but nulldeğer için başarısızlık istiyorsanız formu kullanın:
${var :? error message }
İle :colonyukarıdaki gibi. Bir nulldeğerin başarılı olmasını istiyorsanız , iki nokta üst üste işaretini atlayın. Ayrıca, bir anda göstereceğim gibi, bunu reddedebilir ve yalnızca ayarlanmış değerler için başarısız olabilirsiniz.
Başka bir koşusu _test():
sh <<-\CMD
_test() { echo $( ${empty:?error string} ) &&\
echo "echo still works" ; } 2<<-INIT
${empty?function doesnt run}
INIT
echo "this runs" |\
( _test ; echo "this doesnt" ) ||\
echo "now it prints"
# END
CMD
this runs
sh: line 1: empty: function doesnt run
now it prints
Bu, her türlü hızlı testle çalışır, ancak yukarıda _test(), pipelinebaşarısızlıkların ortasından çalıştığını ve aslında command listalt kabuğun tamamen başarısız olduğunu görürsünüz , çünkü işlevdeki komutların hiçbiri veya aşağıdaki echoçalıştırma hiç olmaz, ancak şimdi yazdırıldığı için kolayca test edilebileceği de gösterilmiştir echo "now it prints" .
Şeytan ayrıntıda gizlenmiş, sanırım. Yukarıdaki durumda, çıkan kabuk komut dosyası değildir , _main | logic | pipelineancak ( subshell in which we ${test?} ) ||küçük bir sanal alan çağrılır.
Ve açık olmayabilir, ancak sadece ters durum veya sadece set=değerler için geçmek istiyorsanız , oldukça basittir:
sh <<-\CMD
N= #N is NULL
_test=$N #_test is also NULL and
v="something you would rather do without"
( #this subshell dies
echo "v is ${v+set}: and its value is ${v:+not NULL}"
echo "So this ${_test:-"\$_test:="} will equal ${_test:="$v"}"
${_test:+${N:?so you test for it with a little nesting}}
echo "sure wish we could do some other things"
)
( #this subshell does some other things
unset v #to ensure it is definitely unset
echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
echo "So this ${_test:-"\$_test:="} will equal NULL ${_test:="$v"}"
${_test:+${N:?is never substituted}}
echo "so now we can do some other things"
)
#and even though we set _test and unset v in the subshell
echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
# END
CMD
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without
Yukarıdaki örnek, POSIX parametre ikamesinin 4 formunun hepsinden ve bunların çeşitli :colon nullveya not nulltestlerinden yararlanır. Yukarıdaki bağlantıda daha fazla bilgi var ve işte yine .
Sanırım _testfonksiyon çalışmalarımızı da göstermeliyiz, değil mi? Sadece empty=somethingfonksiyonumuza bir parametre olarak (veya önceden herhangi bir zamanda) beyan ederiz :
sh <<-\CMD
_test() { echo $( echo ${empty:?error string} ) &&\
echo "echo still works" ; } 2<<-INIT
${empty?tested as a pass before function runs}
INIT
echo "this runs" >&2 |\
( empty=not_empty _test ; echo "yay! I print now!" ) ||\
echo "suspiciously quiet"
# END
CMD
this runs
not_empty
echo still works
yay! I print now!
Bu değerlendirmenin tek başına durduğuna dikkat edilmelidir - başarısız olmak için ek test gerektirmez. Birkaç örnek daha:
sh <<-\CMD
empty=
${empty?null, no colon, no failure}
unset empty
echo "${empty?this is stderr} this is not"
# END
CMD
sh: line 3: empty: this is stderr
sh <<-\CMD
_input_fn() { set -- "$@" #redundant
echo ${*?WHERES MY DATA?}
#echo is not necessary though
shift #sure hope we have more than $1 parameter
: ${*?WHERES MY DATA?} #: do nothing, gracefully
}
_input_fn heres some stuff
_input_fn one #here
# shell dies - third try doesnt run
_input_fn you there?
# END
CMD
heres some stuff
one
sh: line :5 *: WHERES MY DATA?
Ve son olarak orijinal soruya geri dönüyoruz: bir $(command substitution)alt kabuktaki hatalar nasıl ele alınır ? Gerçek şu ki - iki yol var, ama ikisi de doğrudan değil. Sorunun özü, kabuğun değerlendirme sürecidir - kabuk genişletmeleri ( $(command substitution)kabuğun değerlendirme işleminde geçerli kabuk komutu yürütme işleminden daha erken gerçekleşir) - hatalarınız yakalanıp sıkışabildiği zamandır.
Operasyonların yaşadığı sorun, mevcut kabuğun hataları değerlendirdiği zaman, $(command substitution)alt kabuğun yerini almış olmasıdır - hiçbir hata kalmamıştır.
Peki iki yol nedir? Ya bunu $(command substitution)alt kabuğun içinde, onsuz yaptığınız gibi testlerle açıkça yaparsınız ya da sonuçlarını geçerli bir kabuk değişkenine alır ve değerini test edersiniz.
Yöntem 1:
echo "$(madeup && echo \: || echo '${fail:?die}')" |\
. /dev/stdin
sh: command not found: madeup
/dev/stdin:1: fail: die
echo $?
126
Yöntem 2:
var="$(madeup)" ; echo "${var:?die} still not stderr"
sh: command not found: madeup
sh: var: die
echo $?
1
Bu, satır başına bildirilen değişken sayısına bakılmaksızın başarısız olur:
v1="$(madeup)" v2="$(ls)" ; echo "${v1:?}" "${v2:?}"
sh: command not found: madeup
sh: v1: parameter not set
Ve dönüş değeriniz sabit kalır:
echo $?
1
ŞİMDİ TUZAK:
trap 'printf %s\\n trap resurrects shell!' ERR
v1="$(madeup)" v2="$(printf %s\\n shown after trap)"
echo "${v1:?#1 - still stderr}" "${v2:?invisible}"
sh: command not found: madeup
sh: v1: #1 - still stderr
trap
resurrects
shell!
shown
after
trap
echo $?
0
echo $( made up name )ile$( made up name )istenilen davranışı üretir. Yine de bir açıklamam yok.