Herhangi bir komut hatası benim bash komut dosyası otomatik olarak çalıştırmak için bir yolu var mı?


12

Bir sürü komut yapması gereken bir kabuk komut dosyası yazıyorum ve her komut önceki komutlara bağlıdır. Herhangi bir komut başarısız olursa, tüm komut dosyası başarısız olmalıdır ve ben bir çıkış işlevini çağırıyorum. Her komutun çıkış kodunu kontrol edebilirim, ancak etkinleştirebileceğim bir mod olup olmadığını veya bash'ın bunu otomatik olarak yapmasının bir yolunu merak ediyorum.

Örneğin, şu komutları alın:

cd foo || myfunc
rm a || myfunc
cd bar || myfunc
rm b || myfunc


Herhangi bir şekilde başarısız olursa myfunc çağırmalı bu komutları çalıştırmadan önce bir şekilde kabuk sinyal verebilir bir yolu var mı, bunun yerine ben gibi temiz bir şey yazabilirsiniz:

cd foo
rm a
cd bar
rm b

Yanıtlar:


13

Herhangi bir komut sıfırdan büyük bir durum döndürürse ve çıkışta işlevinizi yürütürse komut dosyasından çıkmak için bash trap ERR kullanabilirsiniz .

Gibi bir şey:

myfunc() {
  echo 'Error raised. Exiting!'
}

trap 'myfunc' ERR

# file does not exist, causing error
ls asd
echo 123

Not o bash tuzak ERR örtülü yapar set -o errexitveya set -eve POSIX değildir.

Ve ERRbaşarısız komut, hemen ardından gelen komut listesinin untilveya whileanahtar kelimenin bir parçasıysa, testin ifya da elifayrılmış kelimeleri izleyen bir parçası, bir komutun &&veya ||listede yürütülen bir komutun parçasıysa veya komutun dönüş durumu kullanılarak ters çevriliyorsa , tuzak yürütülmez !.


1

Kabul edilen cevapta (belki de) daha basit bir varyasyon:

  1. set -e Bir komutun bir listenin yürütülmesini durduramamasına neden olmak için kullanın .
  2. Sadece komutlarınızı listeleyin.
  3. Hata işleme komutlarınızı yürütmek için bir if- then- elseifadesi kullanın. Bu son parça biraz zor. İzlemek:
set -e
Eğer
    cmd 1                         # ör. cd foo
     cmd 2                         # ör. rm a
     cmd 3                         # ör. cd çubuğu
     cmd 4                         # ör. rm b
sonra
    set + e
    başarı üzerine yapılacak komutlar (eğer varsa)
Başka
    set + e
    myfunc
    başarısızlık durumunda yapılacak diğer komutlar (varsa) 
fi

Zor kısmı size komutları koymak olmasıdır içine parçasıif arasında if- then- elsedeğil thenkısmen veya elsekısmen. Hatırlanacağı sözdizimi ififadesi olduğunu

eğer  liste ; sonra  sıralayın ; [elif  listesi ; sonra  sıralayın ; ] ... [başka  liste ; ] fi 
   ↑↑↑↑
set -eEğer kabuk söyler ( ) başarısız, o gitmek olmamalı ve yürütmek ( ve böylece satır aşağı üzerine). Bu bir kabuk betiğinin en dış seviyesinde bir komuta olursa, kabuk çıkacaktır. Bununla birlikte, bir · · · bir izlenerek (bileşik) listesi , bu dört komutlardan herhangi başarısızlığı sadece başarısız tüm liste neden olur - neden maddesi yürütülecek. Dört komutun tümü başarılı olursa, yan tümce yürütülür.cmd1cd foocmd2rm acmd1cmd2cmd3cmd4ifelsethen

Her iki durumda da, yapmanız gereken ilk şey eseçeneği yaparak seçeneği devre dışı bırakmak (kapatmak) olabilir set +e. Aksi takdirde, komutta bir komut myfuncbaşarısız olursa komut dosyası sudan çıkabilir .

set -eolup , belirtilen ve POSIX tarifnamede tarif edilen .


0

Kelimenizi " her komut önceki her komut bağlıdır. Herhangi bir komut başarısız olursa tüm komut dosyası başarısız olmalıdır " kelimenin tam anlamıyla, hataları tedavi etmek için herhangi bir özel işlev gerekmez düşünüyorum.

Tek ihtiyacınız olan komutlarınızı tam olarak yazdıklarınızı yapan &&operatör ve ||operatör ile zincirlemek .

Örneğin bu zincir kırdı ve eğer "bir şeyler ters gitti" yazdırır olacak herhangi bir önceki komutları (soldan sağa bash okur) kırdı

cd foo && rm a && cd bar && rm b || echo "something went wrong"

Gerçek örnek (sadece gerçek bir demo için dir foo, dosya a, dir bar ve dosya b oluşturdum):

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm a && cd bar && rm bb || echo "something is wrong"
rm: cannot remove 'bb': No such file or directory
something is wrong #mind the error in the last command

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm aa && cd bar && rm b || echo "something is wrong"
rm: cannot remove 'aa': No such file or directory
something is wrong #mind the error in second command in the row

Son olarak, tüm komutlar başarıyla yürütüldüyse (çıkış kodu 0), komut dosyası devam eder:

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm a && cd bar && rm b || echo "something is wrong"
gv@debian:/home/gv/Desktop/PythonTests/foo/bar$ 
# mind that the error message is not printed since all commands were successful.

Hatırlanması gereken önemli olan, && next komutunun kullanılmasıyla, bash için başarı anlamına gelen 0 kodundan önceki komuttan çıkıldığında yürütülür.

Zincirde herhangi bir komut yanlış giderse, komut / komut dosyası / ne olursa olsun || infaz edilecek.

Ve sadece kayıt için, Kırılan komuta bağlı olarak farklı eylemler gerçekleştirmeniz gerekiyorsa $?, tam olarak önceki komutun çıkış kodunu raporlayan değeri izleyerek klasik komut dosyası ile de yapabilirsiniz (komut başarıyla çalıştırılırsa sıfır döndürür) veya komut başarısız olursa başka bir pozitif sayı)

Misal:

for comm in {"cd foo","rm a","cd bbar","rm b"};do  #mind the error in third command
eval $comm
    if [[ $? -ne 0 ]];then 
        echo "something is wrong in command $comm"
        break
    else 
    echo "command $comm executed succesful"
    fi
done

Çıktı:

command cd foo executed succesfull
command rm a executed succesfull
bash: cd: bbar: No such file or directory
something is wrong in command cd bbar

İpucu: "bash: cd: bbar: Böyle bir dosya yok ..." iletisini uygulayarak gizleyebilirsiniz. eval $comm 2>/dev/null

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.