Bir kısmı başarısız olursa bir kabuk betiğinden nasıl çıkılır?


51

Bir kısmı başarısız olursa, çıkan bir kabuk betiğini nasıl yazabilirim? Örneğin, aşağıdaki kod pasajı başarısız olursa, kodun çıkması gerekir.

n=0
until [ $n -ge 5 ]
do
  gksu *command* && break
  n=$[$n+1]
  sleep 3

Yanıtlar:


88

Bir yaklaşım set -e, betiğinizin başına eklemektir . Bu (dan help set) anlamına gelir :

  -e  Exit immediately if a command exits with a non-zero status.

Bu nedenle, komutlarınızdan herhangi biri başarısız olursa, komut dosyası çıkacaktır.

Alternatif olarak, exitolası hata noktalarına açık ifadeler ekleyebilirsiniz :

command || exit 1

5
Ben (ve bash wiki ) insanların (IMO tarafından tasarlanan kırılmış) set -eözelliğini kullanmak yerine, yanlış düşünmeye bazı düşünceler koyarlar . Burada gerçekten geçerli değil. OP, komutu çalıştırmak için 5 başarısız denemeden sonra komut dosyasından çıkmak istiyor.
Stéphane Chazelas 12:16

1
@ StéphaneChazelas Kırık olup olmadığı konusunda sizinle tartışmayacağım, haklı olduğunuza eminim. Ancak OP, “Bir kısmı başarısız olursa, çıkan bir kabuk betiğini nasıl yazabilirim?” Diye sordu, 5 başarısızlıktan sonra çıkmanın ne olduğunu düşünüyorsunuz?
terdon

Çünkü sorunun yorumlanabileceği başka bir yol düşünemiyorum.
Stéphane Chazelas 12:16

1
@ StéphaneChazelas iyi olabilirsiniz. Kelimenin tam anlamıyla yorumladım: Bir kısmı başarısız olursa tüm script nasıl çıkabiliyor? Ve set -ebunu yapmanın tek yolu bu.
terdon

O senaryo Snippet olarak, tetikleyebilecek komutlar set -eedilir sleep( breaközel yerleşiğini olmanın, script en kabuklarda başarısızlık üzerine çıkmasına neden olur komutları ifveya solundaki &&etkilenmez set -e, n=...eğer başarısız olabilir nsalt okunur ama daha sonra bu komut dosyasından da çıkmadan çıkacaktır set -e), böylece yorumlama oldukça olası görünmemektedir. Sorunun kötü ifade edildiğine katılıyorum.
Stéphane Chazelas 12:16

17

Anahtar kelimeyi kullanarak herhangi bir yerden bir komut dosyasından çıkabilirsiniz exit. Ayrıca, betiğinizin, örneğin exit 1veya exit 2diğerlerinin nasıl başarısız olduğunu veya nasıl olduğunu diğer programlara belirtmek için bir çıkış kodu belirleyebilirsiniz . (Kurallara göre, çıkış kodu 0, başarı için ve 0'dan büyük herhangi bir şey başarısızlık anlamına gelir; 127 üzerindeki kodlar anormal sonlandırma için ayrılmıştır (örneğin, bir sinyal ile).

Başarısızlıktan çıkacak genel yapı şudur:

if [ failure condition ]; then
    exit n
fi

uygun failure conditionve n. Ancak, belirli senaryolarda farklı şekilde ilerleyebilirsiniz. Şimdi, davanız için sorunuzu yorumluyorum, beş gksubaşarısızlıktan herhangi birinin başarısız olması durumunda, o zaman çıkmak istiyorsunuz. Bunun bir yolu, böyle bir işlevi kullanmaktır

function try_command {
    for i in 1 2 3 4 5 ; do
        if gksu command ; then
            return 0
        fi
    fi
    exit 1
}

ve sonra, döngü tarafından çağırılır try_command.

Sorunuzu nasıl ele alacağınızla ilgili (daha fazla) gelişmiş veya karmaşık yollar vardır. Bununla birlikte, yukarıdaki çözüme yeni başlayanlar için Stephane'nin çözümünden daha erişilebilir.


10
attempt=0
until gksu command; do
  attempt=$((attempt + 1))
  if [ "$attempt" -gt 5 ]; then
    exit 1
  fi
done

exitalt kabukta çağrılmadıkça komut dosyasından çıkar. Komut dosyasının bu bölümü bir alt kabuktaysa, örneğin bir boru hattının içinde (...)ya $(...)da içinde olduğundan , yalnızca o alt kabuktan çıkar .

Bu durumda, betiğin alt kabuğa ek olarak çıkmasını istiyorsanız, exito alt kabuğun çıkmasını çağırmanız gerekir .

Örneğin, burada 2 yuvalanmış alt kabuk seviyesi bulunur:

(
  life=hard
  output=$(
    echo blah
    [ "$life" = easy ] || exit 1 # exit subshell
    echo blih not run
  ) || exit # if the subshell exits with a non-zero exit status,
            # exit as well with the same exit status

  echo not run either
) || exit # if the subshell exits with a non-zero exit status,
          # exit as well with the same exit status

Alt kabuk bir boru hattının parçasıysa daha zor olabilir. bashözel sahiptir $PIPESTATUSbenzer dizi zshs' $pipestatusburada size yardımcı olabilir one:

{
   echo foo
   exit 1
   echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
  exit "$subshell_ret"
fi

3

Tuzak bir sinyal aldıktan sonra bir eylem gerçekleştirir.

trap "echo EXIT;  exit" 0
trap "echo HUP;   exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT;  exit" 3
trap "echo ERR;   exit" ERR
n=0
until [ $n -ge 5 ]
do
  n=$[$n+1]
  echo $n
  sleep 3
done

Bunu çalıştırın ve normal şekilde çıkmasına izin verin. 0 sinyalinde tutulur.

EXIT

Tekrar çalıştır ve ^ C ile kes. Hem sinyal 2 hem de sinyal 0'da tuzak kurar.

CTL-C
EXIT

Sıfır olmayan bir çıkış durumu ERR'ye kapanacak

ERR
EXIT
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.