Not: zsh
Buradaki ö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 expansion
test etmek ${empty?} _test()
hala return
s sonuncu evinced gibi - bir pas echo
Bu 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 echo
umursamıyor - 's bol mutlu bir tek hizmet etmek \newline; echo
olduğ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ı, sh
kabuk 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 Null
veya Unset.
parametre ayarlanmadan ya da boşsa, expansion of word
olacaktır (bu işaret eder ya da bir mesajı kelimesi atlanırsa ayarlanmadan) written to standard error
ve 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 null
değer için başarısızlık istiyorsanız formu kullanın:
${var
:? error message }
İle :colon
yukarıdaki gibi. Bir null
değ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()
, pipeline
başarısızlıkların ortasından çalıştığını ve aslında command list
alt 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 | pipeline
ancak ( 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 null
veya not null
testlerinden yararlanır. Yukarıdaki bağlantıda daha fazla bilgi var ve işte yine .
Sanırım _test
fonksiyon çalışmalarımızı da göstermeliyiz, değil mi? Sadece empty=something
fonksiyonumuza 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.