“Bash -e” kullanırken bir alt kabuğun çıkış ve çıkış değerini nasıl alabilirim?


70

Aşağıdaki kodu göz önünde bulundurun

outer-scope.sh

#!/bin/bash
set -e
source inner-scope.sh
echo $(inner)
echo "I thought I would've died :("

inner-scope.sh

#!/bin/bash
function inner() { echo "winner"; return 1; }

outer-scope.shBir çağrı inner()başarısız olduğunda çıkmaya çalışıyorum . Yana $()bir alt kabuk çağırır, bu olmaz.

İşlevin sıfır olmayan bir çıkış koduyla çıkabileceği gerçeğini koruyarak bir işlevin çıktısını nasıl alabilirim?

Yanıtlar:


102

$()çıkış durumunu korur; sadece bir görev gibi kendi statüsüne sahip olmayan bir ifadede kullanmanız gerekir.

çıkış = $ (iç)

Bundan sonra $?, çıkış durumunu içerecektir ve innerbunun için her türlü kontrolü kullanabilirsiniz:

output=$(inner) || exit $?
echo $output

Veya:

if ! output=$(inner); then
    exit $?
fi
echo $output

Veya:

if output=$(inner); then
    echo $output
else
    exit $?
fi

(Not: exitArgümanları olmayan bir çıplak eşittir exit $?- yani, son komutun çıkış durumuyla çıkar. İkinci formu sadece netlik için kullandım.)


Ayrıca, kayıt için: sourcebu durumda tamamen ilgisizdir. Sadece tanımlayabilirsiniz inner()içinde outer-scope.shaynı sonuçlarla, dosyaya.


Neden bu kadar, $ olsa bile? betiğin otomatik olarak çıkmadığı $ () çıkış durumunu içeriyor mu (-e ayarlanmışsa)? EDIT: boşuna, sorularıma cevap verdiğini düşünüyorum, teşekkürler!
jabalsad

Emin değilim. (Yukarıdakilerin hiçbirini test etmedim.) Ayrıca, eğer hakkında soru soruyorsanız echo $(), bunun nedeni, alt satırların çıkış kodlarının, echokomut satırı - bir çıkış koduna (genellikle 0) sahip olduğu zaman göz ardı edilmemesi olabilir .
Grawity

1
Hmm, yazdığımda if ! $(exit 1) ; then echo $?; fianladım 0. ifBu çıkış değerini korumanız gerekirse gideceğiniz yol kesin değil .
Ron Burk,

@grawity - Bu Dash ile çalışıyor mu? Sinir bozucu bir Autoconf davranışı etrafında çalışmaya çalışıyorum (yani, Sun veya IBM'in derleyicisi terminalde yasadışı seçeneği yazdırdığında, Autoconf raporlama başarısı ).
jww

3
if ! output=$(inner); then exit $?; fi0 dönüş kodu ile $?çıkacak çünkü dönüş kodu !yerine dönüş kodunu verecek inner. İstediğiniz davranışı elde edebilirsiniz if output=$(inner); then : ; else exit $?; fiancak bu açık bir şekilde daha ayrıntılı
SJL

26

BashFAQ / 002'ye bakınız :

Her ikisini de istiyorsanız (çıkış ve çıkış durumu):

output=$(command)
status=$? 

Özel Bir Durum

Yerel değişkenleri olan zor bir vaka hakkında not alın, aşağıdaki kodu karşılaştırın:

f() { local    v=$(echo data; false); echo output:$v, status:$?; }
g() { local v; v=$(echo data; false); echo output:$v, status:$?; }

Alacağız:

$ f     # fooled by 'local' with inline initialization
output:data, status:0

$ g     # a good one
output:data, status:1

Neden?

Bir alt kabuğun çıktısı bir localdeğişkeni başlatmak için kullanıldığında , çıkış durumu artık alt kabuğun değil, olması muhtemel olan komutun durumudur .local 0

Ayrıca bakınız https://stackoverflow.com/a/4421282/537554


3
Bu soruyu gerçekten cevaplamadıysa da, bugün benim için faydalı oldu, yani +1.
fourpastmidnight

1
Bash komutlarının çıkış durumu her zaman yürütülen son komutun durumudur. Güçlü yazılmış dillerde çok fazla zaman geçirdiğimizde, "yerel" in bir tür belirtici değil, başka bir komut olduğunu unutmak kolaydır. Bu noktayı burada tekrarladığınız için teşekkür ederim, bugün bana yardımcı oldu.
markeissler

2
Vay canına, şimdi tam olarak bu konuyla karşılaştım ve sen düzelttin. Teşekkürler!
krb686

4
#!/bin/bash
set -e
source inner-scope.sh
foo=$(inner)
echo $foo
echo "I thought I would've died :("

Ekleyerek echo, alt kabuk tek başına durmaz (ayrı ayrı kontrol edilmez) ve iptal olmaz. Atama bu sorunu çözüyor.

Bunu yapabilir ve daha sonra işlemek için çıktıyı bir dosyaya yeniden yönlendirebilirsiniz.

tmpfile=$( mktemp )
inner > $tmpfile
cat $tmpfile
rm $tmpfile

Tabii ki, $ tmpfile ikinci değişkende var olmaya devam ediyor ...
Daniel Beck
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.