Saya telah membaca banyak pertanyaan tentang berbagai situs pertukaran stack dan unix forum bantuan tentang cara memodifikasi opsi shell dan kemudian mengembalikannya - yang paling komprehensif yang saya temukan di sini adalah di Bagaimana "membatalkan" a `set -x`?
The kebijaksanaan yang diterima tampaknya baik menyimpan dari hasil set +o
atau shopt -po
kemudian eval
nanti untuk mengembalikan pengaturan sebelumnya.
Namun, dalam pengujian saya sendiri dengan bash 3.x dan 4.x, errexit
opsi tidak disimpan dengan benar saat melakukan penggantian perintah.
Berikut ini contoh skrip untuk menunjukkan masalah:
set -o errexit
set -o nounset
echo "LOCAL SETTINGS:"
set +o
OLDOPTS=$(set +o)
echo
echo "SAVED SETTINGS:"
echo "$OLDOPTS"
Dan output (saya memangkas beberapa variabel yang tidak relevan):
LOCAL SETTINGS:
set -o errexit
set -o nounset
SAVED SETTINGS:
set +o errexit
set -o nounset
Ini sepertinya sangat berbahaya. Kebanyakan skrip yang saya tulis bergantung pada errexit
penghentian eksekusi jika ada perintah yang gagal. Saya baru saja menemukan bug di salah satu skrip saya yang disebabkan oleh ini, di mana fungsi yang seharusnya mengembalikan errexit
pada akhirnya berakhir dengan menimpanya, mengaturnya kembali ke default off selama durasi skrip.
Yang ingin saya lakukan adalah menulis fungsi yang dapat mengatur opsi sesuai kebutuhan dan kemudian mengembalikan semua opsi dengan benar sebelum keluar. Tetapi tampaknya seolah-olah dalam subkulit dipanggil oleh substitusi perintah, errexit
tidak diwarisi.
Saya bingung bagaimana cara menyelamatkan hasil set +o
tanpa menggunakan substitusi perintah atau melompat melalui lingkaran FIFO. Saya dapat membaca dari $SHELLOPTS
tetapi eval
formatnya tidak bisa ditulis atau dalam -able.
Saya tahu salah satu alternatifnya adalah menggunakan fungsi subshell , tapi itu memperkenalkan banyak sakit kepala karena bisa mencatat output dan juga mengembalikan beberapa variabel.
Mungkin terkait: /programming/29532904/bash-subshell-errexit-semantics (sepertinya ada solusi untuk bash 4.4 dan yang lebih tinggi, tetapi saya lebih suka memiliki solusi portabel)
shopt
opsi set bash (seperti nullglob).Jawaban:
Apa yang Anda lakukan harus berhasil. Tapi bash mematikan
errexit
opsi di pergantian perintah, jadi itu mempertahankan semua opsi kecuali yang ini. Ini khusus untuk bash dan khusus untukerrexit
opsi. Bash tetap dipertahankanerrexit
saat menjalankan dalam mode POSIX. Sejak bash 4.4, bash juga tidak jelaserrexit
dalam substitusi perintah jikashopt -s inherit_errexit
berlaku.Karena opsi ini dimatikan sebelum kode apa pun berjalan di dalam substitusi perintah, Anda harus memeriksanya di luar.
Jika Anda tidak menyukai kompleksitas ini, gunakan zsh sebagai gantinya.
sumber
bash4.4
sekarang memilikilocal -
(à laash
) sebagai setara denganzsh
'ssetopt localoptions
(atau apa yang ksh88 lakukan secara default)shopt -s lastpipe; set +o | IFS= read -rd '' OLDOPTS || :
(dua set pilihan adalahbash
keistimewaan lain).OLDOPTS="$(set +o); set -$-"
.Setelah mencoba yang lama di atas pada alpine 3.6, saya sekarang telah mengambil pendekatan yang jauh lebih sederhana:
sesuai dokumentasi, "$ -" menyimpan daftar opsi yang sedang aktif. Tampaknya bekerja dengan baik, apakah saya melewatkan sesuatu?
sumber
set -uf
)errexit
disebarkan ke dalam proses substitusi.Memeriksa:
Versi bash:
sumber
Solusi sederhana adalah menambahkan
errexit
pengaturan keOLDOPTS
:Selesai
sumber
[[ -o errexit ]]
(ksh / bash / zsh) dan[ -o errexit ]
(bash / ksh / yash)shopt
adalah perintah yang valid untuk bash, tidak ada alasan yang berarti untuk menghindarinya (saya hanya masalah preferensi pribadi Anda tentang bagaimana jawaban harus ditulis). Bukan perubahan yang berarti. @ StéphaneChazelas