Belirli bir komut için bash ihmal hatası


444

Aşağıdaki seçenekleri kullanıyorum

set -o pipefail
set -e

Bash komut dosyasında hata durumunda yürütmeyi durdurmak için. Ben ~ 100 satır komut dosyası yürütme var ve ben komut dosyasında her satırın dönüş kodunu kontrol etmek istemiyorum.

Ancak belirli bir komut için hatayı yok saymak istiyorum. Bunu nasıl yapabilirim?

Yanıtlar:


757

Çözüm:

particular_script || true

Misal:

$ cat /tmp/1.sh
particular_script()
{
    false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three asla basılmayacak.

Ayrıca, açıkken pipefail, borudaki komutlardan biri sıfır olmayan çıkış koduna sahip olduğunda tüm borunun sıfır olmayan çıkış koduna sahip olduğunu düşünmek için yeterli olduğunu eklemek istiyorum ( pipefailkapalı olan sonuncusu olmalıdır) .

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0

15
+1. Bash Referans El Kitabında açıklandığı gibi , -ebaşarısız olan komut bir whileveya untilanahtar kelimenin hemen ardından gelen komut listesinin bir parçası, bir ififadedeki testin bir parçası, yürütülen herhangi bir komutun bir parçasıysa "Özellik ayarlandığında kabuk çıkmaz" bir de &&ya ||nihai aşağıdaki komutla dışında listenin &&veya ||herhangi bir komut bir boru hattı ama geçen, veya komutun dönüş durumu ile ters olup olmadığını !."
ruakh

@IgorChubin Neden bilmiyorum ama bu çalışmaz çıktı = (ldd $2/bin/* || true) | grep "not found" | wc -lkomut ldd dönüş hatası olduğunda bu satırdan sonra sona eriyor
Vivek Goel

1
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
Igor Chubin

1
yüzünden set -o pipefail. zaman grepbuluntular hiçbir şey, eğer sıfır çıkış kodu döndürür ve kabuk tüm boru sıfır olmayan çıkış kodu olduğunu düşünmek için yeterli olacaktır.
Igor Chubin

3
Dönüş değerini (çıkış yapmadan) koruma seçeneğini istiyorsanız, mycommand && true komutunu deneyin. Bu, sonraki adımlarda dönüş kodunu kontrol etmenizi ve programlı olarak işlemenizi sağlar.
Ed Ost

179

Sadece || truehatayı yoksaymak istediğiniz komuttan sonra ekleyin .


11
Ben bunu eklemek önemli olduğunu düşünüyorum: bu yöntem, yanıt kodu ve hata mesajı devam ederken izin verirken "!" Aşağıda açıklanan yöntem yanıt kodunu değiştirir ve bu nedenle hatayı oluşturmaz. Bu, set -ebir hata mesajını kullanırken ve yakalamaya çalışırken önemlidir : örneğinset -e; TEST=$(foo 2>&1 || true); echo $TEST
Spanky

88

Durma ve çıkış durumunu kaydetme

Belirli bir komut başarısız olduğunda komut dosyanızın durmamasını ve başarısız komutun hata kodunu kaydetmek istiyorsanız:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE

2
Tam da ihtiyacım olan şey bu
sarink

nedense benim için çalışmıyor ... oh iyi
Jeef

Komut 0 döndüğünde EXIT_CODE sıfıra ayarlanmamıştır. Ancak sıfır olmayan çıkış kodları da yakalanır. Neden olduğu hakkında bir fikrin var mı?
Ankita13

@ Ankita13 Çünkü sıfır olsaydı ilk commandbaşarılı oldu ve sonra olanı çalıştırmaya ihtiyaç var ||. şöyle okuyun: commandbaşarısız olursa yapın EXIT_CODE=$?. Muhtemelen command || echo "$?"daha ayrıntılı hata ayıklama için "tuzak" yapabilir veya kullanabilirsiniz.
Şuna

63

Daha kısaca:

! particular_script

Gönderen POSIX şartname ile ilgili olarak set -e(vurgu mayın):

Bu seçenek açık olduğunda, Kabuk Hatalarının Sonuçları bölümünde listelenen nedenlerden herhangi biri için basit bir komut başarısız olursa veya> 0 çıkış durumu değeri döndürürse ve bir süre, anahtar veya anahtar kelime varsa bileşik listenin bir parçası değilse ve VE veya VEYA listesinin bir parçası değildir ve önünde bir! ayrılmış kelime , sonra kabuk hemen çıkacaktır.


16
Bu sadece bir komutun çıkış kodunu tersine çevirir, bu nedenle başarıyla bitirilen komut 0 yerine 1 döndürür ve komut dosyası ile başarısız olur -e.
Marboni

17
Anladığım kadarıyla, !kabuğun ne olursa olsun çıkmasını engelleyecek. Bu komut dosyası , Still alive!çalıştırdığımda iletiyi tamamladığını belirten iletiyi görüntüler . Farklı davranışlar görüyor musunuz?
Lily Finley

7
haklısın, çıkış durumunu tersine çevirir, ancak komut hem 0 hem de 1 ile sona erdiğinde komut dosyasını kilitlemez. Dikkatsizdim. Her neyse, belgeleri alıntıladığınız için teşekkür ederim, ifademi ifmaddeye koydum ve sorunu çözdüm.
Marboni

42

"True döndürme" yerine, "noop" veya null yardımcı programını da ( POSIX teknik özelliklerinde belirtildiği gibi ) kullanabilir :ve yalnızca "hiçbir şey yapamazsınız". Birkaç harf kaydedeceksiniz. :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."

3
Buna rağmen ||: || kadar net değil doğru (uzman olmayan kullanıcıların kafasını karıştırabilir), özlülükten hoşlanırım
David

Bu varyant, CI için önemli olabilecek herhangi bir metni döndürmez.
1919'da

5

Komut dosyanızın başarısız olmasını önlemek ve dönüş kodunu toplamak istiyorsanız :

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

returncode komut başarılı veya başarısız olursa olsun toplanır.


2

CLI araçlarıyla çalışırken aşağıdaki snippet'i kullanıyorum ve bazı kaynakların var olup olmadığını bilmek istiyorum, ancak çıktıyı umursamıyorum.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi

1
Bu gerçekten dolambaçlı ve orta derecede pahalı bir yol gibi görünüyorif [ -r not_exist ]
üçlü

1

Bu çözümü beğendim:

: `particular_script`

Geri keneler arasındaki komut / komut dosyası yürütülür ve çıktısı ":" ("true" değerine eşdeğer olan) komutuna beslenir.

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

düzenleme: çirkin yazım hatası düzeltildi



0

Buradan benim için hiçbir çözüm işe yaramadı, bu yüzden başka bir çözüm buldum:

set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e

Bu CI ve CD için kullanışlıdır. Bu şekilde hata mesajları yazdırılır, ancak komut dosyasının tamamı yürütülmeye devam eder.


0
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status

Günlük dosyası oluşturmak için buna örnek

log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}

output=$(*command* 2>&1) && exit_status=$? || exit_status=$?

if [ "$exit_status" = 0 ]
    then
        event="$output"
        log_event
    else
        event="ERROR $output"
        log_event
fi

0

Yukarıdaki basit çözüm için teşekkürler:

<particular_script/command> || true

Aşağıdaki yapı, komut dosyası adımlarının ve ek akış denetimi seçeneklerinin ek eylemleri / sorun giderme işlemleri için kullanılabilir:

if <particular_script/command>
then
   echo "<particular_script/command> is fine!"
else
   echo "<particular_script/command> failed!"
   #exit 1
fi

Diğer eylemleri ve exit 1gerekirse frenleyebiliriz .

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.