Saya mengamati beberapa perilaku aneh saat menggunakan set -e
( errexit
), set -u
( nounset
) bersama dengan perangkap ERR dan EXIT. Mereka tampaknya terkait, sehingga menempatkan mereka dalam satu pertanyaan tampaknya masuk akal.
1) set -u
tidak memicu jebakan ERR
Kode:
#!/bin/bash trap 'echo "ERR (rc: $?)"' ERR set -u echo ${UNSET_VAR}
- Diharapkan: ERR trap dipanggil, RC! = 0
- Aktual: ERR trap tidak dipanggil, RC == 1
- Catatan:
set -e
tidak mengubah hasilnya
2) Menggunakan set -eu
kode keluar dalam perangkap EXIT adalah 0 bukan 1
Kode:
#!/bin/bash trap 'echo "EXIT (rc: $?)"' EXIT set -eu echo ${UNSET_VAR}
- Diharapkan: EXIT trap dipanggil, RC == 1
- Aktual: EXIT trap disebut, RC == 0
- Catatan: Saat menggunakan
set +e
, RC == 1. Perangkap EXIT mengembalikan RC yang tepat saat ada perintah lain yang melempar kesalahan. - Sunting: Ada posting SO tentang topik ini dengan komentar menarik yang menunjukkan bahwa ini mungkin terkait dengan versi Bash yang digunakan. Menguji cuplikan ini dengan Bash 4.3.11 menghasilkan RC = 1, jadi itu lebih baik. Sayangnya meningkatkan Bash (dari 3.2.51) pada semua host tidak mungkin saat ini, jadi kami harus datang dengan beberapa solusi lain.
Adakah yang bisa menjelaskan perilaku ini?
Pencarian topik-topik ini tidak terlalu berhasil, yang agak mengejutkan mengingat jumlah posting pada pengaturan dan jebakan Bash. Ada satu utas forum , tetapi kesimpulannya agak tidak memuaskan.
set -e
dan set -u
keduanya dirancang khusus untuk membunuh shell scripted. Menggunakan mereka dalam kondisi yang dapat memicu aplikasi mereka akan mematikan shell scripted. Tidak ada jalan keluarnya, kecuali untuk tidak menggunakannya, dan sebagai gantinya untuk menguji kondisi-kondisi tersebut ketika mereka berlaku dalam urutan kode. Jadi, pada dasarnya, Anda dapat menulis kode-shell yang baik, atau dapat Anda gunakan set -eu
.
-u
tidak akan memicu perangkap ERR (ini adalah kesalahan, jadi seharusnya tidak memicu perangkap) atau kode kesalahan adalah 0 bukannya 1. yang terakhir sepertinya adalah bug yang sudah diperbaiki di versi yang lebih baru, jadi begitu. Tetapi bagian pertama cukup sulit untuk dipahami jika Anda belum menyadari bahwa kesalahan dalam evaluasi shell (ekspansi parameter) dan kesalahan aktual dalam perintah tampaknya merupakan dua hal yang berbeda. Untuk solusinya, seperti yang Anda sarankan, saya sekarang mencoba untuk menghindari -eu
dan memeriksa secara manual ketika diperlukan
(set -u; : $UNSET_VAR)
dan serupa. Hal-hal semacam ini bisa bagus juga - Anda dapat menjatuhkan banyak sekali-sekali &&
:, (set -e; mkdir dir; cd dir; touch dirfile)
jika Anda mengerti maksud saya. Hanya saja itu adalah konteks yang terkontrol - ketika Anda menetapkannya sebagai opsi global, Anda kehilangan kendali dan menjadi terkontrol. Namun, biasanya ada solusi yang lebih efisien.
bash
putus dengan standar dan mulai menempatkan jebakan dalam subkulit. Perangkap seharusnya dieksekusi di lingkungan yang sama dari mana datang kembalinya, tetapibash
belum melakukan itu untuk sementara waktu.