Bash mengabaikan kesalahan untuk perintah tertentu

444

Saya menggunakan opsi berikut

set -o pipefail
set -e

Dalam skrip bash untuk menghentikan eksekusi karena kesalahan. Saya memiliki ~ 100 baris eksekusi skrip dan saya tidak ingin memeriksa kembali kode setiap baris dalam skrip.

Tetapi untuk satu perintah tertentu, saya ingin mengabaikan kesalahan. Bagaimana saya bisa melakukan itu?

Vivek Goel
sumber

Jawaban:

757

Solusinya:

particular_script || true

Contoh:

$ 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 tidak akan pernah dicetak.

Juga, saya ingin menambahkan bahwa ketika pipefaildinyalakan, cukup bagi shell untuk berpikir bahwa seluruh pipa memiliki kode keluar bukan nol ketika salah satu perintah dalam pipa memiliki kode keluar non-nol (dengan pipefailoff itu harus yang terakhir) .

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0
Igor Chubin
sumber
15
+1. Sebagaimana dijelaskan oleh Manual Referensi Bash , "Shell tidak keluar" ketika -eatribut disetel "jika perintah yang gagal adalah bagian dari daftar perintah segera mengikuti whileatau untilkata kunci, bagian dari tes dalam ifpernyataan, bagian dari setiap perintah yang dieksekusi dalam daftar &&atau ||kecuali perintah yang mengikuti akhir &&atau ||, perintah apa pun dalam pipa tetapi yang terakhir, atau jika status pengembalian perintah sedang terbalik dengan !. "
ruakh
@IgorChubin Saya tidak tahu mengapa tetapi ini tidak berfungsi output = (ldd $2/bin/* || true) | grep "not found" | wc -lscript berakhir setelah baris ini ketika ldd kembali gagal
Vivek Goel
1
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
Igor Chubin
1
karena set -o pipefail. ketika greptidak menemukan apa pun, ia mengembalikan kode keluar non-nol dan cukup bagi shell untuk berpikir bahwa seluruh pipa memiliki kode keluar non-nol.
Igor Chubin
3
Jika Anda menginginkan opsi untuk mempertahankan nilai pengembalian (tanpa keluar), Anda dapat mencoba perintah && true. Ini memungkinkan Anda untuk memeriksa kode pengembalian dalam langkah-langkah selanjutnya dan menanganinya secara terprogram.
Ed Ost
178

Tambahkan saja || truesetelah perintah di mana Anda ingin mengabaikan kesalahan.

Lars Kotthoff
sumber
11
Saya pikir penting untuk menambahkan ini: metode ini akan memungkinkan kode respons dan pesan kesalahan tetap ada, sedangkan "!" metode yang diuraikan di bawah ini akan mengubah kode respons dan karenanya tidak menghasilkan kesalahan. Ini penting ketika menggunakan set -edan mencoba menangkap pesan kesalahan: mis.set -e; TEST=$(foo 2>&1 || true); echo $TEST
Spanky
87

Jangan berhenti dan simpan juga status keluar

Untuk jaga-jaga jika Anda ingin skrip Anda tidak berhenti jika perintah tertentu gagal dan Anda juga ingin menyimpan kode kesalahan perintah gagal:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE
Arslan Qadeer
sumber
2
Inilah yang saya butuhkan
sarink
tidak bekerja untuk saya untuk beberapa alasan ... oh well
ampun
EXIT_CODE tidak disetel ke nol ketika perintah kembali 0. Kode keluar bukan nol ditangkap. Ada yang tahu kenapa?
Ankita13
@ Ankita13 Karena jika nol, yang pertama commandberhasil dan perlu menjalankan apa yang terjadi setelah ||. membacanya sebagai: jika commandgagal, lakukan EXIT_CODE=$?. Anda mungkin bisa melakukan command || echo "$?"atau menggunakan "trap" untuk debugging verbose yang lebih banyak. Lihat ini -> stackoverflow.com/a/6110446/10737630
tinnick
63

Lebih ringkas:

! particular_script

Dari spesifikasi POSIX mengenai set -e(penekanan tambang):

Ketika opsi ini aktif, jika perintah sederhana gagal karena salah satu alasan yang tercantum dalam Konsekuensi Kesalahan Shell atau mengembalikan nilai status keluar> 0, dan bukan bagian dari daftar senyawa setelah beberapa saat, sampai, atau jika kata kunci, dan bukan bagian dari daftar AND atau OR, dan bukan saluran pipa yang didahului oleh! kata dilindungi undang-undang , maka shell akan segera keluar.

Lily Finley
sumber
16
Ini hanya membalikkan kode keluar dari suatu perintah, jadi perintah yang selesai dengan sukses akan mengembalikan 1 bukan 0 dan gagal skrip dengan -e.
Marboni
17
Pemahaman saya adalah bahwa !akan mencegah shell keluar tidak peduli apa pun. Skrip ini menampilkan pesan Still alive!ketika saya menjalankannya, menunjukkan bahwa skrip berjalan hingga selesai. Apakah Anda melihat perilaku yang berbeda?
Lily Finley
7
Anda benar, ini membalikkan status keluar, tetapi skrip tidak macet ketika perintah berakhir dengan 0 atau 1. Saya kurang perhatian. Ngomong-ngomong, terima kasih telah mengutip dokumentasi, saya menempatkan ekspresi saya untuk ifklausa dan memecahkan masalah.
Marboni
42

Alih-alih "mengembalikan true", Anda juga dapat menggunakan utilitas "noop" atau null (sebagaimana dimaksud dalam spesifikasi POSIX ) :dan hanya "tidak melakukan apa-apa". Anda akan menyimpan beberapa surat. :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."
Timo
sumber
3
meskipun | |: tidak sejelas || true (yang mungkin membingungkan pengguna yang bukan pakar), saya suka keringkasannya
David
Varian ini tidak mengembalikan teks apa pun yang penting dalam CI.
kivagant
5

Jika Anda ingin mencegah skrip Anda gagal dan mengumpulkan kode kembali:

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

set -e

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

returncode dikumpulkan tidak peduli apakah perintah berhasil atau gagal.

volingo
sumber
2

Saya telah menggunakan potongan di bawah ini ketika bekerja dengan alat CLI dan saya ingin tahu apakah ada sumber daya atau tidak, tapi saya tidak peduli dengan hasilnya.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi
Payman
sumber
1
Ini sepertinya cara yang benar-benar bundaran dan cukup mahal untuk mengatakannyaif [ -r not_exist ]
tripleee
1

Saya suka solusi ini:

: `particular_script`

Perintah / skrip di antara tick kembali dieksekusi dan outputnya dimasukkan ke perintah ":" (yang setara dengan "true")

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

sunting: Memperbaiki kesalahan ketik yang jelek

Q-life
sumber
0

sementara || trueyang disukai, tetapi Anda juga bisa melakukannya

var=$(echo $(exit 1)) # it shouldn't fail
Foto Blysk
sumber
0

Tidak ada solusi yang berfungsi untuk saya dari sini, jadi saya menemukan solusi lain:

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

Ini berguna untuk CI & CD. Dengan cara ini pesan kesalahan dicetak tetapi keseluruhan skrip terus dijalankan.

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

Contoh penggunaan ini untuk membuat file log

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
Robert.C
sumber
0

Terima kasih atas solusi sederhana di sini dari atas:

<particular_script/command> || true

Konstruksi berikut dapat digunakan untuk tindakan tambahan / pemecahan masalah langkah skrip dan opsi kontrol aliran tambahan:

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

Kami dapat mengerem tindakan lebih lanjut dan exit 1jika diperlukan.

Almaz Gareev
sumber