İç içe döngülerle kabuk komut dosyasından çıkma


11

İç içe döngüler ile bir kabuk komut dosyası var ve sadece "çıkış" gerçekten komut dosyası, ama yalnızca geçerli döngü çıkmadı öğrendim. Belirli bir hata durumunda komut dosyasından tamamen çıkmanın başka bir yolu var mı?

"Set -e" kullanmak istemiyorum, çünkü kabul edilebilir hatalar var ve çok fazla yeniden yazma gerektiriyor.

Şu anda, işlemi manuel olarak öldürmek için kill kullanıyorum, ancak bunu yapmanın daha iyi bir yolu olmalı gibi görünüyor.


1
Ne demek "çıkış" betiğinden gerçekten çıkmıyor? Sadece dene bash -c 'for x in y z; do exit; done; echo "This never gets printed"'.
Chris Down

Haklısın, normalde iç içe döngülerden çıkmalı, ancak çıkış kullandığımda komut dosyam dış döngü ile devam ediyor. Senaryoyu gönderemiyorum.
user923487

2
Neden sorunu gösteren bir komut dosyası yazıp buraya gönderemiyorsunuz? Bu bana pek olası gelmiyor.
Toby Speight

1
İç döngü kodunuzdaki bir alt kabukta gerçekleşiyor mu?
Toby Speight

@Toby Komut dosyasının çoğu günlük kaydı için bir alt kabukta, ancak hem döngüler hem de kodun geri kalanı aynı alt kabukta.
user923487

Yanıtlar:


19

Sorununuz iç içe döngüler değil. İç döngülerinizin biri veya daha fazlası bir alt kabukta çalışıyor .

Bu çalışıyor:

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        for j in $(seq 1 10) ; do
                echo j $j
                sleep 1
                [[ $j = 3 ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        echo "After the j loop."
done
echo "After all the loops."

çıktı:

i 1
j 1
j 2
j 3
I've had enough!

Bu, tanımladığınız sorunu sunar:

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        cat /etc/passwd | while read line; do
                echo LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        echo "After the j loop."
done    
echo "After all the loops."

çıktı:

i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 2
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 3
LINE root:x:0:0:root:/root:/bin/bash
(...etc...)

İşte çözüm; alt kabuklarda çalışan iç döngülerin dönüş değerini test etmeniz gerekir:

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        cat /etc/passwd | while read line; do
                echo LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        err=$?; [[ $err != 0 ]] && exit $err
        echo "After the j loop."
done
echo "After all the loops."

Testi not edin: [[ $? != 0 ]] && exit $?

çıktı:

i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!

Düzenleme: Hangi alt kabuk bulunduğunuzu doğrulamak için, "yanıt" komut dosyasını, geçerli kabuğunuzun işlem kimliğinin ne olduğunu bildirmek üzere değiştirin. NOT: Bu yalnızca bash 4'te çalışır:

#!/bin/bash

for i in $(seq 1 100); do
        echo pid $BASHPID i $i
        cat /etc/passwd | while read line; do
                echo pid $BASHPID LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        err=$?; [[ $err != 0 ]] && echo pid $BASHPID && exit $err
        echo "After the j loop."
done
echo "After all the loops."

çıktı:

pid 31793 i 1
pid 31796 LINE root:x:0:0:root:/root:/bin/bash
pid 31796 LINE bin:x:1:1:bin:/bin:/sbin/nologin
pid 31796 LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
pid 31793

"İ" ve "j" değişkenleri size Fortran'ın iznini getirdi. İyi günler dilerim. :-)


Hem iç hem de dış döngü aynı alt kabukta çalışıyor, bu yüzden içten çıkmak her ikisinden de çıkmalı mı? Sorunu kendim üretirken sorun yaşıyorum. Program mantığının çoğunu kaldırdığımda sorun ortadan kalktı. Her neyse, bunu şimdilik cevap olarak işaretleyeceğim, çünkü muhtemelen bir şeyler yapmak zorunda.
user923487

Verdiğiniz bağlantıyı okuduktan sonra sorunu bulduğumu düşünüyorum. Dış döngüde "cat file | okuma satırında" yapıyorum. Borulama bir alt kabuk oluşturur. Bunu bilmiyordum.
user923487

@ user923487 - Güncellenmiş cevabımı görün. Bash 4'ünüz varsa, alt kabuk pidini yankılayabilir (veya printf, modernseniz) ve alt kabukta olup olmadığınızı doğrulayabilirsiniz. Bash sürümünüzü görmek için bash --versionkomut satırına yazın.
Mike S

Çok yararlı. Teşekkürler! Her ne kadar "killall scriptname.sh" demek zorunda kalsam da bunu çözmenin en kolay yolu gibi görünüyor.
user923487

2

Daha önceki cevabı kullanarak önerir [[ $? != 0 ]] && exit $?ancak bu olmaz oldukça beklendiği gibi çünkü işi [[ $? != 0 ]]testi sıfırlanır $?, sıfıra hangi araçları tekrar o halde olacak komut dosyası beklendiği gibi erken çıkmak, bu olacak hep kodu 0 ile çıkış (beklenmemektedir gibi) . Ayrıca, dize karşılaştırma testinden -neziyade sayısal karşılaştırma testini kullanmak daha iyi olur !=. Dolayısıyla IMHO daha iyi bir çözüm kullanmaktır:

err=$?; [[ $err -ne 0 ]] && exit $err

bu kadar emin olalım asıl çıkış kodu doğru ayarlanır.


İyi geri bildirim. Kodu düzelttim.
Mike S

1

Kullanabilirsiniz break.

Gönderen help break:

Exit a FOR, WHILE or UNTIL loop.  If N is specified, break N enclosing loops.

Bu nedenle, üç çevreleyen döngüden çıkmak için, yani ana iç içe yerleştirilmiş iki iç içe döngünüz varsa, tüm bunlardan çıkmak için bunu kullanın:

break 3

Döngülerden sonra daha fazla kod var, bu yüzden sadece bunlardan kurtulmak yeterli değil.
user923487

1
harika teşekkürler! örnekfor((i=0;i<3;i++));do echo A;for((j=0;j<2;j++));do echo B;break 2;done;done
Kova Gücü

0

exit tüm kabuğu veya geçerli alt kabuğu sonlandırır:

$ bash -c 'for i in 1 2 3; do for j in 4 5 6; do echo $i; exit 1; echo $j; done; done'
1
$ echo $?
1
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.