Perilaku "eval" di bawah "set -e" dalam ekspresi bersyarat

9

Pertimbangkan perintahnya

eval false || echo ok
echo also ok

Biasanya, kami mengharapkan ini untuk mengeksekusi falseutilitas dan, karena status keluar tidak nol, untuk kemudian jalankan echo okdan echo also ok.

Dalam semua POSIX-seperti kerang saya gunakan ( ksh93, zsh, bash, dash, OpenBSD ksh, dan yash), ini adalah apa yang terjadi, tetapi hal-hal menarik jika kita aktifkan set -e.

Jika set -eberlaku, OpenBSD's shdan kshshells (keduanya berasal dari pdksh) akan mengakhiri skrip saat menjalankan eval. Tidak ada shell lain yang melakukan itu.

POSIX mengatakan bahwa kesalahan dalam utilitas built-in khusus (seperti eval) harus menyebabkan shell non-interaktif berakhir. Saya tidak sepenuhnya yakin apakah mengeksekusi falsemerupakan "kesalahan" (jika ya, itu akan terlepas dari set -eaktif).

Cara untuk mengatasi ini tampaknya adalah dengan meletakkan evaldi sub shell,

( eval false ) || echo ok
echo also ok

Pertanyaannya adalah apakah saya harus melakukan itu di skrip shell POSIX-ly yang benar, atau apakah itu bug di shell OpenBSD? Juga, apa yang dimaksud dengan "kesalahan" dalam teks POSIX yang ditautkan ke atas?


Info ekstra: Kerang OpenBSD akan menjalankan perintah echo okdengan dan tanpa set -e di perintah

eval ! true || echo ok

Kode asli saya terlihat seperti

set -e
if eval "$string"; then
    echo ok
else
    echo not ok
fi

yang tidak akan menghasilkan not okdengan string=falsemenggunakan kerang OpenBSD (itu akan berakhir), dan saya tidak yakin itu karena desain, kesalahan atau kesalahpahaman, atau sesuatu yang lain.

Kusalananda
sumber
eval falsemenghasilkan status non-nol jadi saya berharap set -euntuk mengakhiri skrip pada saat itu. Dalam hal ! set -etidak berlaku sebagai !pernyataan secara eksplisit memeriksa status keluar.
fcbsd
@ fcbsd Apakah Anda berharap eval falseuntuk menghentikan skrip walaupun itu bagian dari daftar AND-OR atau pernyataan kondisional? Saya tidak akan.
Kusalananda
Saya tidak yakin apakah set -ediatur jika itu adalah perilaku yang benar ... Saya setuju bahwa masuk akal untuk tidak mengakhiri dalam pernyataan bersyarat.
fcbsd
telah memainkan lebih banyak, dengan sh pada CentOS 7 - Saya akan mengatakan bahwa itu adalah perilaku yang dimaksudkan untuk ksh / sh OpenBSD saat menggunakan set -esehingga `()` adalah jawabannya.
fcbsd

Jawaban:

4

Bahwa tidak ada shell lain yang memerlukan penyelesaian seperti itu adalah indikasi kuat bahwa itu adalah bug di OpenBSD ksh. Bahkan, ksh93 tidak menunjukkan masalah seperti itu.

Bahwa ada ||di dalam baris perintah harus menghindari keluar shell yang disebabkan oleh kode kembali 1 di sebelah kiri itu.

Kesalahan dari khusus built-in akan menyebabkan keluar dari shell non interaktif acording POSIX tapi itu tidak selalu benar. Mencoba continuekeluar dari loop adalah kesalahan, dan continuemerupakan kesalahan bawaan. Tetapi sebagian besar shell tidak keluar pada:

continue 3

Sebuah builtin yang memancarkan kesalahan yang jelas tetapi tidak keluar.

Jadi, jalan keluar falsedihasilkan oleh set -ekondisi bukan oleh karakteristik builtin dari perintah ( evaldalam hal ini).

Kondisi pasti yang set -eakan keluar cukup kabur di POSIX.

Ishak
sumber
Ini menggemakan respons yang saya dapatkan dari milis OpenBSD, tetapi dengan lebih banyak kata, terima kasih! Saya akan memilah laporan bug yang tepat, dan jika tidak ada yang terjadi, saya akan melihat sendiri kode sumbernya.
Kusalananda
4

[maaf jika ini bukan jawaban yang nyata, saya akan memperbaruinya ketika saya memperbaikinya]

Saya telah melihat kode sumber, dan kesimpulan saya adalah:

1) Ini adalah bug / batasan, tidak ada filosofis di baliknya.

2) "perbaikan" dari garpu portabel ksh ( mksh) OpenBSD sangat buruk, hanya memperburuk keadaan, tanpa benar-benar memperbaikinya:

Bug baru, berbeda dari semua cangkang lain:

mksh -ec 'eval "false; echo yup"'
yup

bash -ec 'eval "false; echo yup"'
(nothing)

Masih belum benar-benar diperbaiki:

mksh -ec 'eval "set -e; false" || echo yup'
(nothing)

bash -ec 'eval "set -e; false" || echo yup'
yup

Anda dapat mengganti bashatas dengan dash, zsh, yash, ksh93, dll

mosvy
sumber