Cegah grep keluar jika terjadi nomatch

29

Script ini tidak menggema "setelah":

#!/bin/bash -e

echo "before"

echo "anything" | grep e # it would if I searched for 'y' instead

echo "after"
exit

Itu juga akan terjadi jika saya menghapus -eopsi pada baris shebang, tetapi saya ingin menyimpannya sehingga skrip saya berhenti jika ada kesalahan. Saya tidak menganggap grep menemukan kecocokan sebagai kesalahan. Bagaimana saya dapat mencegahnya keluar begitu tiba-tiba?

iago-lito
sumber
Ini adalah pengamatan yang dimaksudkan hanya untuk pertimbangan. Mungkin logika naskah ini harus dipikirkan lagi. Jika tidak penting untuk menemukan string, mengapa mencarinya? Definisi grep sedemikian rupa sehingga seseorang membuat keputusan berdasarkan ada atau tidaknya suatu string. Jika Anda tidak peduli, maka itu tidak penting. Juga, tampaknya -eAnda mengira Anda benar-benar peduli: sedemikian rupa sehingga masalah apa pun adalah bencana besar.
Andrew Falanga
2
@AndrewFalanga Saya sangat peduli karena saya benar-benar menganalisis konten var=$(complex command | grep complex_pattern)yang mungkin nol (dalam hal ini program saya seharusnya tidak berakhir). Ini hanyalah skrip rebus yang membuat masalah terjadi. Tidak ada lubang hitam metafisik dalam logika di sini, kan? ;)
iago-lito
Mengetahui sekarang bahwa Anda bermaksud untuk menangkap hasil tidak mengklarifikasi beberapa hal. Seperti yang disajikan, itu membingungkan saya.
Andrew Falanga

Jawaban:

33
echo "anything" | grep e || true

Penjelasan:

$ echo "anything" | grep e
### error
$ echo $?
1
$ echo "anything" | grep e || true
### no error
$ echo $?
0
### DopeGhoti's "no-op" version
### (Potentially avoids spawning a process, if `true` is not a builtin):
$ echo "anything" | grep e || :
### no error
$ echo $?
0

"||" berarti "atau". Jika bagian pertama dari perintah "gagal" (artinya "grep e" mengembalikan kode keluar non-nol) maka bagian setelah "||" dieksekusi, berhasil dan mengembalikan nol sebagai kode keluar ( trueselalu mengembalikan nol).

John N.
sumber
3
Versi yang sedikit lebih pendek dari yang sama yang tidak berputar /bin/trueadalah: command || :(jadi dalam kasus Anda, set -e; grep 'needle' haystack || :).
DopeGhoti
1
@DopeGhoti, trueadalah built-in di beberapa shell (setidaknya pada bash 4.3pada RHEL)
iruvar
3
Tidak valid karena jika perintah pertama gagal itu akan menyembunyikan kesalahan. Solusi yang benar harus mengembalikan bukan nol jika perintah pertama dalam pipa gagal.
Sorin
11

Cara tangguh untuk mengirim pesan dengan aman dan opsional grep :

echo something | grep e || [[ $? == 1 ]] ## print 'something', $? is 0
echo something | grep x || [[ $? == 1 ]] ## no output, $? is 0
echo something | grep --wrong-arg e || [[ $? == 1 ]] ## stderr output, $? is 1

Menurut manual posix , kode keluar 1 berarti tidak ada baris yang dipilih, dan> 1 berarti kesalahan.

James ZM Gao
sumber
1
Ini harus menjadi jawaban yang diterima, karena hanya menekan kode keluar peringatan (1) jika grep tidak menemukan apa pun, namun ia meneruskan kesalahan yang sebenarnya (kode keluar> 1). Solusi lain di sini selalu menekan kesalahan yang sebenarnya, yang biasanya buruk.
HaroldFinch
7

Opsi lain adalah menambahkan perintah lain ke dalam pipeline - yang tidak gagal:

echo "anything" | grep e | cat

Karena catsekarang perintah terakhir dalam pipa, itu status keluar cat, bukan grep, yang akan digunakan untuk menentukan apakah pipa gagal atau tidak.

roelvanmeer
sumber
4

Pilihan lain:

...
set +e
echo "anything" | grep e
set -e
...
Jeff Schaller
sumber
3

Larutan

#!/bin/bash -e

echo "before"

echo "anything" | grep e || : # it would if I searched for 'y' instead

echo "after"
exit

Penjelasan

set -e atau set -o errexit

Segera keluar jika saluran pipa (yang mungkin terdiri dari satu perintah sederhana ), daftar , atau perintah gabungan (lihat di SHELL GRAMMARatas), keluar dengan status bukan nol. Shell tidak keluar jika perintah yang gagal adalah bagian dari daftar perintah segera mengikuti kata kunci whileatau until, bagian dari tes mengikuti kata-kata ifatau elifdicadangkan, bagian dari perintah yang dieksekusi dalam daftar &&atau ||kecuali perintah mengikuti akhir &&atau ||, setiap perintah dalam pipa tetapi yang terakhir, atau jika nilai pengembalian perintah sedang terbalik!. Jika perintah majemuk selain subkulit mengembalikan status tidak nol karena perintah gagal saat -esedang diabaikan, shell tidak keluar. Jebakan aktif ERR, jika disetel, dieksekusi sebelum shell keluar. Opsi ini berlaku untuk lingkungan shell dan setiap lingkungan sub-shell secara terpisah (lihat di COMMAND EXECUTION ENVIRONMENTatas), dan dapat menyebabkan subkulit keluar sebelum menjalankan semua perintah dalam subkulit.

Plus, :adalah perintah tanpa efek di Bash.

Cyker
sumber