Alt kabuktan kabuk betiğinden çık


30

Bu pasajı göz önünde bulundurun:

stop () {
    echo "${1}" 1>&2
    exit 1
}

func () {
    if false; then
        echo "foo"
    else
        stop "something went wrong"
    fi
}

Normal funcolarak çağrıldığında, komut dosyasının sonlandırılmasına neden olur, bu amaçlanan davranıştır. Ancak, aşağıdaki gibi bir alt kabukta yürütülürse,

result=`func`

komut dosyasından çıkmaz. Bu, çağıran kodun her seferinde fonksiyonun çıkış durumunu kontrol etmesi gerektiği anlamına gelir. Bundan sakınmanın bir yolu var mı? Bunun set -eiçin mi?


1
stderr'e bir mesaj basan ve betiği durduran bir işlev "stop" istiyorum, ancak stop çağırması işlevi bir alt kabukta yürütüldüğünde durmuyor, örneğin
Ernest AC

2
Tabii ki, mevcut olandan değil alt kabuktan çıkıyor. Basitçe işlevi doğrudan çağırmak: func.

1
doğrudan arayamıyorum çünkü değişkende saklanması gereken bir dize döndürüyor
Ernest AC

1
@ErnestAC Lütfen asıl sorudaki tüm detayları sağlayın. Yukarıdaki işlev bir dize döndürmez.

1
@ htor Örneği değiştirdim
Ernest AC

Yanıtlar:


10

Sen olabilir orijinal kabuk (öldürmek kill $$çağırmadan önce) exitve bu çalışma muhtemelen olur. Fakat:

  • bana oldukça çirkin görünüyor
  • orada ikinci bir alt kabuğunuz varsa kırılır, yani bir alt kabuğun içinde bir alt kabuk kullanın.

Bunun yerine, Bash SSS’de bir değeri geri almak için çeşitli yollardan birini kullanabilirsiniz . Çoğu maalesef pek iyi değil. Her bir işlev çağrısından sonra sadece hataları denetlemekte sıkışmış olabilirsiniz ( -eçok fazla sorun var ). Ya öyle ya da Perl'e geç.


5
Teşekkürler. Yine de Python'a geçmeyi tercih ederim.
Ernest AC

2
Yazdığım gibi, 2019 yılı. Birine "Perl'e geçiş yapmam" demek saçma. Çekişmeli olduğum için özür dilerim, ama IMO'ya eşdeğer olan Cobol'a geçiş yapmak için 'C' ile sinirli olan birine söyler misiniz? Ernest'in işaret ettiği gibi, Python çok daha iyi bir seçimdir. Benim tercihim Ruby olurdu. Her iki şekilde de, Perl'den başka bir şey yok.
Graham Nicholls

38

Örneğin, çıkış durumunun 77 herhangi bir alt kabuk seviyesinden çıkış anlamına geldiğine karar verebilirsiniz ve

set -E
trap '[ "$?" -ne 77 ] || exit 77' ERR

(
  echo here
  (
    echo there
    (
      exit 12 # not 77, exit only this subshell
    )
    echo ici
    exit 77 # exit all subshells
  )
  echo not here
)
echo not here either

set -EERRTuzaklar ile birlikte biraz set -ekendi hata işleme tanımlamanıza olanak sağlayan , geliştirilmiş bir versiyonu gibi .

Zsh ERR tuzakları ihtiyacınız kalmaz, otomatik devralınan set -E, ayrıca olarak tuzakları tanımlayabilirsiniz TRAPERR()fonksiyonları ve bunları yoluyla değiştirmek $functions[TRAPERR]gibifunctions[TRAPERR]="echo was here; $functions[TRAPERR]"


1
İlginç çözüm! Açıkça daha zarif kill $$.

3
Dikkat edilmesi gereken bir şey, bu tuzak enterpolasyonlu komutları işlemeyecek, örneğin echo "$(exit 77)"; senaryo biz echo ""
yazmışız

İnterresting! -E'de olmayan (oldukça eski) bashta hiç şans var mı? Belki de bir USER sinyali üzerindeki bir tuzağı tanımlamaya ve bu sinyale bir öldürmeyi kullanmaya başvurmalıyız? Ben de biraz araştırma yapacağım ...
Olivier Dulac 18

77 yerine 1 dönmek için bir deniz kabuğu tuzağı olmadığında nasıl bilebilirim?
saat

7

Alternatif olarak kill $$, deneyebilirsiniz kill 0, yuvalanmış alt kabuklar halinde çalışacaktır (tüm arayanlar ve yan işlem sinyali alır)… ama yine de acımasız ve çirkin.


2
Bu işlem 0 kimliğini öldürmez mi?
Ernest AC

5
Bu tüm süreç grubunu öldürür. İstemediğiniz şeylere vurabilirsiniz (örneğin, arka planda bazı şeyler başlattıysanız).
derobert 18:12

2
@ErnestAC kill (2) man sayfasını görün, çukurların ≤0 özel bir anlamı var.
derobert 18:12

0

Bunu dene ...

stop () {
    echo "${1}" 1>&2
    exit 1
}

func () {
    if $1; then
        echo "foo"
    else
        stop "something went wrong"
    fi
}

echo "shell..."
func $1

echo "subshell..."
result=`func $1`

echo "shell..."
echo "result=$result"

Elde ettiğim sonuçlar ...

# test_exitsubshell true
shell...
foo
subshell...
shell...
result=foo
# test_exitsubshell false
shell...
something went wrong

notlar

  • ifTestin yapılabilmesi için parametreleştirildi trueveya false(2 çalışmaya bakın)
  • Ne zaman ifbir testtir false, biz altkabuk ulaşamayacaklar.

Bu, kullanıcının yayınladığı ve çalışmadığı söylenen orijinal fikre çok benzer. Bunun denizaltı davası için işe yaradığını sanmıyorum. Yanlış kullanarak testiniz "shell" davasından sonra çıkar ve asla "subshell" test durumuna girmez. Alt kabuk "exit 1" çağrısından çıkacağından ancak hatayı dış kabuğa yaymadığından bu durumun başarısız olacağına inanıyorum.
stuckj

0

(Bash'e özgü cevap) Bash'in istisnalar kavramı yoktur. Bununla birlikte, -o errexit (veya eşdeğeri: set -e) 'nin en dış seviyedeki setinde başarısız komut, alt kabuğun sıfır olmayan bir çıkış durumuyla çıkmasına neden olacaktır. Bu, bu alt kabukların çalıştırılması etrafında koşulsuz bir iç içe alt kabuklar kümesiyse, tüm komut dosyasını etkin bir şekilde toplar ve çıkar.

Bu, çeşitli bash kodunun bitlerini daha büyük bir betiğe dahil etmeye çalışırken zor olabilir. Bir parça bash kendi başına işe yarayabilir, ancak errexit (veya errexit olmadan) yapıldığında beklenmedik şekillerde davranır.

[192.168.13.16 (f0f5e19e) ~ 22:58:22] # bash -o errexit / tmp / foo
bir şeyler yanlış gitti
[192.168.13.16 (f0f5e19e) ~ 22:58:31] # bash / tmp / foo
bir şeyler yanlış gitti
Ama yine de buraya geldik
[192.168.13.16 (f0f5e19e) ~ 22:58:37] # kedi / tmp / foo
#! / Bin / bash
durdurmak () {
    yankı "$ {1}"
    çıkış 1
}

eğer yanlışsa; sonra
    yankı "foo"
Başka
    (
        dur "bir şeyler ters gitti"
    )
    echo "Ama yine de buraya geldik"
fi
[192.168.13.16 (f0f5e19e) ~ 22:58:40] #

-2

Bir liner'den çıkmak için örneğim:

COMAND || ( echo "ERROR – executing COMAND, exiting..." ; exit 77 );[ "$?" -eq 77 ] && exit

1
Bu aslında OP'nin istediği gibi alt mermilerde çalışan komutla çalışacak bir cevap gibi gözükmüyor ... Bu cevap verilen aşağı oylara katılmıyorum. Yorumsuz veya sebepsiz aşağı oylar, kötü cevaplar kadar yararsızdır.
DVS
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.