Bahasa yang tepat digunakan dalam spesifikasi UNIX Tunggal untuk menggambarkan artiset -e
adalah:
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 [perintah kondisional atau negasi], maka shell akan segera keluar.
Ada ambiguitas tentang apa yang terjadi ketika perintah seperti itu terjadi dalam subkulit . Dari sudut pandang praktis, semua yang dapat dilakukan subshell adalah keluar dan mengembalikan status bukan nol ke shell induk. Apakah shell induk akan pada gilirannya keluar tergantung pada apakah status bukan nol ini diterjemahkan menjadi perintah sederhana yang gagal di shell induk.
Satu kasus bermasalah seperti itu adalah yang Anda temui: status pengembalian yang bukan nol dari substitusi perintah . Karena status ini diabaikan, itu tidak menyebabkan shell induk untuk keluar. Seperti yang sudah Anda temukan , cara untuk mengambil status keluar ke akun adalah dengan menggunakan substitusi perintah dalam penugasan sederhana : maka status keluar dari penugasan adalah status keluar dari substitusi perintah terakhir dalam penugasan .
Perhatikan bahwa ini akan berfungsi sebagaimana dimaksud hanya jika ada substitusi perintah tunggal, karena hanya status substitusi terakhir yang diperhitungkan. Misalnya, perintah berikut ini berhasil (baik sesuai dengan standar dan dalam setiap implementasi yang saya lihat):
a=$(false)$(echo foo)
Kasus lain yang harus diperhatikan adalah subshells eksplisit : (somecommand)
. Menurut interpretasi di atas, subshell dapat mengembalikan status bukan nol, tetapi karena ini bukan perintah sederhana di shell induk, shell induk harus melanjutkan. Faktanya, semua cangkang yang saya tahu membuat orang tua kembali pada saat ini. Meskipun ini berguna dalam banyak kasus seperti di (cd /some/dir && somecommand)
mana tanda kurung digunakan untuk menjaga operasi seperti perubahan direktori saat ini lokal, itu melanggar spesifikasi jika set -e
dimatikan dalam subkulit, atau jika subkulit mengembalikan status bukan nol dengan cara yang tidak akan menghentikannya, seperti menggunakan !
perintah yang benar. Misalnya, semua abu, bash, pdksh, ksh93, dan zsh keluar tanpa menampilkan foo
contoh berikut:
set -e; (set +e; false); echo "This should be displayed"
set -e; (! true); echo "This should be displayed"
Namun tidak ada perintah sederhana yang gagal saat set -e
diberlakukan!
Kasus bermasalah ketiga adalah elemen dalam pipa nontrivial . Dalam praktiknya, semua kerang mengabaikan kegagalan elemen-elemen pipa selain yang terakhir, dan menunjukkan salah satu dari dua perilaku mengenai elemen pipa terakhir:
- ATT ksh dan zsh, yang menjalankan elemen terakhir dari pipeline di shell induk, berbisnis seperti biasa: jika perintah sederhana gagal di elemen terakhir pipeline, shell mengeksekusi perintah itu, yang kebetulan adalah shell induk, keluar.
- Kerang lain memperkirakan perilaku dengan keluar jika elemen terakhir dari pipa mengembalikan status bukan nol.
Seperti sebelumnya, mematikan set -e
atau menggunakan negasi pada elemen terakhir dari pipa menyebabkannya mengembalikan status bukan-nol dengan cara yang seharusnya tidak menghentikan shell; kerang selain ATT ksh dan zsh akan keluar.
pipefail
Opsi Bash menyebabkan pipa keluar segera di bawah set -e
jika salah satu elemennya mengembalikan status bukan nol.
Perhatikan bahwa sebagai komplikasi lebih lanjut, bash dimatikan set -e
dalam subkulit kecuali dalam mode POSIX ( set -o posix
atau ada POSIXLY_CORRECT
di lingkungan saat bash dimulai).
Semua ini menunjukkan bahwa spesifikasi POSIX sayangnya melakukan pekerjaan yang buruk dalam menentukan -e
opsi. Untungnya, cangkang yang ada sebagian besar konsisten dalam perilaku mereka.
set -e; (cd /nonexisting)
.(Menjawab pertanyaan saya sendiri karena saya sudah menemukan solusinya). Salah satu solusinya adalah selalu menetapkan ini ke variabel perantara. Dengan cara ini kode pengembalian (
$?
) diatur.Begitu
Akan menampilkan
1
(atau sebaliknya keluar jikaset -e
ada), namun:Akan ditampilkan
0
setelah baris kosong. Kode return dari echo (atau perintah lain yang dijalankan dengan output backtick) akan menggantikan kode 0 return.Saya masih terbuka untuk solusi yang tidak memerlukan variabel perantara, tetapi ini membuat saya mendapatkan beberapa cara.
sumber
Seperti yang ditunjukkan OP dalam jawabannya sendiri, menugaskan output dari sub-perintah ke variabel benar-benar menyelesaikan masalah; yang
$?
tersisa tanpa cedera.Namun, satu kasus tepi masih dapat membingungkan Anda dengan negatif palsu (mis. Perintah gagal tetapi kesalahan tidak muncul),
local
deklarasi variabel:local myvar=$(subcommand)
akan selalu kembali0
!bash(1)
tunjukkan ini:Berikut ini adalah contoh uji sederhana:
Hasil:
sumber
VAR=...
danlocal VAR=...
benar - benar membuatku bingung!Seperti yang orang lain katakan,
local
akan selalu kembali 0. Solusinya adalah mendeklarasikan variabel terlebih dahulu:Keluaran:
sumber
Untuk keluar dari kegagalan substitusi perintah, Anda dapat secara eksplisit mengatur
-e
subshell, seperti ini:sumber
Poin menarik!
Saya tidak pernah sengaja menemukan itu, karena saya bukan teman
set -e
(Sebaliknya saya lebih sukatrap ... ERR
) tetapi sudah diuji bahwa:trap ... ERR
juga tidak menangkap kesalahan dalam$(...)
(atau backticks mode lama).Saya pikir masalahnya adalah (seperti yang sering terjadi) bahwa di sini sebuah subkulit disebut dan
-e
secara eksplisit berarti shell saat ini .Hanya solusi lain yang muncul saat ini adalah menggunakan baca:
Ini melempar
ERR
dan dengan-e
shell akan dihentikan. Satu-satunya masalah: ini hanya berfungsi untuk perintah dengan satu garis output (atau Anda menyalurkan melalui sesuatu yang bergabung dengan garis).sumber