Menjalankan exit
subkulit adalah satu perangkap:
#!/bin/bash
function calc { echo 42; exit 1; }
echo $(calc)
Script mencetak 42, keluar dari subkulit dengan kode kembali 1
, dan melanjutkan dengan skrip. Bahkan mengganti panggilan dengan echo $(CALC) || exit 1
tidak membantu karena kode balik echo
adalah 0 terlepas dari kode balik calc
. Dan calc
dieksekusi sebelum echo
.
Yang lebih membingungkan adalah menggagalkan efek exit
dengan membungkusnya menjadi local
builtin seperti pada script berikut. Saya tersandung masalah ketika saya menulis fungsi untuk memverifikasi nilai input. Contoh:
Saya ingin membuat file bernama "year month day.log", yaitu 20141211.log
untuk hari ini. Tanggal tersebut diinput oleh pengguna yang mungkin gagal memberikan nilai wajar. Oleh karena itu, dalam fungsi saya, fname
saya memeriksa nilai balik date
untuk memverifikasi validitas input pengguna:
#!/bin/bash
doit ()
{
local FNAME=$(fname "$1") || exit 1
touch "${FNAME}"
}
fname ()
{
date +"%Y%m%d.log" -d"$1" 2>/dev/null
if [ "$?" != 0 ] ; then
echo "fname reports \"Illegal Date\"" >&2
exit 1
fi
}
doit "$1"
Kelihatan bagus. Biarkan skrip diberi nama s.sh
. Jika pengguna memanggil skrip ./s.sh "Thu Dec 11 20:45:49 CET 2014"
, file 20141211.log
dibuat. Namun, jika tipe pengguna ./s.sh "Thu hec 11 20:45:49 CET 2014"
, maka skrip menghasilkan:
fname reports "Illegal Date"
touch: cannot touch ‘’: No such file or directory
Baris fname…
mengatakan bahwa data input buruk telah terdeteksi di subkulit. Tetapi exit 1
pada akhir local …
baris tidak pernah dipicu karena local
arahan selalu kembali 0
. Ini karena local
dieksekusi setelah $(fname)
dan dengan demikian menimpa kode kembali. Dan karena itu, skrip berlanjut dan memanggil touch
dengan parameter kosong. Contoh ini sederhana tetapi perilaku bash bisa sangat membingungkan dalam aplikasi nyata. Saya tahu, programmer sebenarnya tidak menggunakan penduduk setempat
Untuk memperjelas: Tanpa local
, skrip dibatalkan seperti yang diharapkan ketika tanggal yang tidak valid dimasukkan.
Cara mengatasinya adalah dengan membagi garis seperti
local FNAME
FNAME=$(fname "$1") || exit 1
Perilaku aneh sesuai dengan dokumentasi local
di dalam halaman manual bash: "Status pengembalian adalah 0 kecuali lokal digunakan di luar fungsi, nama tidak valid diberikan, atau nama adalah variabel readonly."
Meskipun bukan bug, saya merasa bahwa perilaku bash adalah berlawanan dengan intuisi. Saya menyadari urutan eksekusi, local
tidak harus menutupi tugas yang rusak, namun.
Jawaban awal saya berisi beberapa ketidaktepatan. Setelah diskusi yang mendalam dan mendalam dengan mikeserv (terima kasih untuk itu) saya pergi untuk memperbaikinya.