Bu komut dosyasını for döngüsünün sonucuna göre hata çıkışına nasıl alabilirim?


13

set -o errexitHata durumunda tüm komut dosyası hata noktasında çıktığı kullanan bir bash komut dosyası var .
Komut dosyası, curlbazen istenen dosyayı alamayan bir komut çalıştırır - ancak bu durumda komut dosyası çıkışta hata vermez.

İçin bir fordöngü ekledim

  1. birkaç saniye duraklatın, ardından curlkomutu yeniden deneyin
  2. falsevarsayılan sıfır dışında bir çıkış durumu tanımlamak için for döngüsünün altında kullanın - curl komutu başarılı olursa döngü sona erer ve son komutun çıkış durumu sıfır olmalıdır.
#! /bin/bash

set -o errexit

# ...

for (( i=1; i<5; i++ ))
do
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    if [ -f ~/.vim/autoload/pathogen.vim ]
    then
        echo "file has been retrieved by curl, so breaking now..."
        break;
    fi

    echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
    sleep 5
    # exit with non-zero status so main script will errexit
    false

done

# rest of script .....

Sorun, curlkomut başarısız olduğunda, döngü komutu beş kez yeniden dener - tüm denemeler başarısız olursa for döngüsü sona erer ve ana komut dosyası devam eder errexit.
Bu curlifade başarısız olursa komut dosyasının tamamını nasıl kapatabilirim ?

Yanıtlar:


18

Değiştir:

done

ile:

done || exit 1

Bu, fordöngü sıfır dışında bir çıkış koduyla çıkarsa kodun çıkmasına neden olur .

Bir trivia noktası olarak, 1in exit 1gerekli değildir. İndirme başarısız olursa exitson çalıştırılan komutun çıkış durumuyla birlikte düz bir komut çıkacaktır false(kod = 1). İndirme başarılı olursa, döngünün çıkış kodu echokomutun çıkış kodudur . echonormalde kod = 0 ile çıkar, önemli ölçüde başarı. Bu durumda, ||tetiklemez ve exitkomut yürütülmez.

Son olarak, set -o errexitsürprizlerle dolu olabileceğini unutmayın . Artıları ve eksileri hakkında bir tartışma için Greg'in SSS # 105'e bakın .

belgeleme

Gönderen man bash:

için ((ifade1; ifade2; ifade3)); yapılacaklar listesi; tamam
İlk olarak, aritmetik ifade expr1 kuralları ARİTMETİK DEĞERLENDİRİLMESİ altında açıklanan göre değerlendirilir. Aritmetik ifade expr2 daha sonra sıfır olarak değerlendirilene kadar tekrar tekrar değerlendirilir. İfade2 sıfırdan farklı bir değere her değerlendirildiğinde, liste yürütülür ve ifade3 ifade aritmetik ifadesi değerlendirilir. Herhangi bir ifade atlanırsa, 1 olarak değerlendirilirmiş gibi davranır . Dönüş değeri, yürütülen listedeki son komutun çıkış durumudur veya ifadelerden herhangi biri geçersizse false olur. [Vurgu eklendi]


trueBreak ifadesinin önüne koymak ve döngünün çıkış değerini sağlamak iyi bir fikir olabilir mi?
RobertL

1
Açık olanın örtük olmaktan daha iyi olduğunu düşünüyorum . Bu yüzden exit 1düz exitçalıştığı zaman yazdım . Yine de bu bir tarz meselesidir ve diğerlerinin kendi fikirleri olabilir.
John1024

1
güzel çalışıyor! teşekkürler :) şahsen ben exitdüz bir çıkış olarak okumak istiyorsunuz - bu kendi başına komut dosyası sonlandırır. exit 1 bana başka bir sürece (yani errexit) bir "sinyal" olarak okurdu exit 1. - bu yüzden gittim exitama açıklama için teşekkürler
the_velour_fog

1
Senaryonuz çünkü bir hata durumunun çıkan ise, gereken çağrı exit 1. Bu hiç etkilenmez errexit. Sadece çağrı programına bir şeylerin yanlış gittiğini söyler. falseKomut bir ifade içeriyor: exit(1). Unix komutlarının% 99,9'u başarıda 0, hatada sıfırdan farklı bir değerle döner. Senin de olmalı.
RobertL

2

Eğer varsa errexitayarlayın, ardından falseaçıklamalar derhal çıkmak için komut neden olmalıdır. curlKomut başarısız olursa da aynı şey geçerli .

Örnek komut dosyanız, yazıldığı gibi, errexit ayarlanmışsa ilk curlkomut başarısızlığından sonra ilk çağırdığında falseçıkmalıdır.

Nasıl çalıştığını görmek için ( -eayarlamak için kısayolu kullanıyorum errexit:

$ ( set -e;  false; echo still here )
$

$ ( set +e;  false; echo still here )
still here
$

Yani eğer curlbir kereden fazla komutu yürütür, bu yazı bulunmamaktadır errexitseti.


1
set -ebundan daha incedir. Bu olacak değil bir döngü içinde ilk başarısız komutundan sonra çıkın. (set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )Kodun falsedört kez çalıştığını belirterek bunu kendiniz kanıtlayabilirsiniz . Daha fazla bilgi set -eiçin Greg'in SSS # 105 sayfasına bakın .
John1024

@ John1024 Teşekkürler. Bu aşağı ve aşağı iniyor.
RobertL

@ John1024 Ama sanırım hala kanıtlanmadı errexit. Lütfen mantığı sorudaki komut dosyasına uygulayın. Bunu çalıştırın: (set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here ) Evet if while || &&vb dönüş değerlerini sınamak errexit tetiklemez. Orijinal komut dosyası ||for döngüsünü almadı .
RobertL

Sadece set -o errexitörnek kodumda komut göstermediğini fark ettim , şimdi ekledim - ve benim için beklendiği gibi çıkma hatası değildi. Ben falsefor döngüsünde son komut olarak tutmak gerekiyordu , sonra ile döngü kapatın done || exit [1]- o zaman güzel çalıştı!
the_velour_fog

@RobertL Ne demek istediğini anlıyorum.
John1024

1

set -o errexit döngülerde ve alt kabuklarda zor olabilir, çünkü işlemin dışına çıkmanız gerekir.

Bir döngüyü kırmak (normal çalışmada bile) kötü uygulama olarak kabul edilir. İki koşul için bir for-loop yerine bir while-loop'u tercih etmem için bana eski okul diyebilirsiniz, ancak okumayı daha iyi buluyorum:

i=1
RET=-1
while [ $i -le 5 ] && [ $RET -ne 0 ]; do
    [ $i -eq 1 ] || sleep 5
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    RET=$?
    i=$((i+1))
done
exit $RET

0

Eğer errexitayarlanırsa ve curlkomut başarısız olursa, komut dosyası başarısız curl komutundan hemen sonra sona erer. Bash kılavuzunda set -e, bir bileşik komutunda tek bir arızalı dönüş durumunu göz ardı eden bir ipucu yoktur . Bu yalnızca bileşik komutun set -eyok sayıldığı bir bağlamda yürütülmesi durumunda olur .
https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin

RobertL tarafından yayınlanan biraz uyarlanmış bir örneği deneyin. Bu, false komutundan hemen sonraki ilk yinelemede durur:

( set -e; for (( i=1; i<5; i++ )); do echo $i; false; echo "${i}. iteration done"; done ; echo "loop done" )

0

Kıvrılma komutuna --fail seçeneğini ekleyebilir, bu sorununuzu çözer, kıvrılma komutu başarısız olursa komut dosyası başarısız olur ve hata verir, eğer jenkins boru hattında kıvrılma kullanılırken de çok faydalıysa:

curl -LSso --fail ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
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.