การดำเนินการexit
ใน subshell เป็นหนึ่งหลุมพราง:
#!/bin/bash
function calc { echo 42; exit 1; }
echo $(calc)
สคริปต์พิมพ์ 42 ออกจากsubshellด้วยโค้ดส่งคืน1
และดำเนินการต่อกับสคริปต์ แม้เปลี่ยนการโทรโดยecho $(CALC) || exit 1
ไม่ได้ช่วยเพราะการกลับมาของรหัสecho
เป็น 0 calc
โดยไม่คำนึงถึงรหัสการกลับมาของ และจะดำเนินการไปก่อนcalc
echo
ยิ่งทำให้งงงวยก็คือการขัดขวางผลกระทบของการexit
ห่อไว้ในlocal
builtin เช่นในสคริปต์ต่อไปนี้ ฉันสะดุดปัญหาเมื่อฉันเขียนฟังก์ชั่นเพื่อตรวจสอบค่าอินพุต ตัวอย่าง:
ฉันต้องการสร้างไฟล์ชื่อ "year month day.log" เช่น20141211.log
สำหรับวันนี้ วันที่จะถูกป้อนโดยผู้ใช้ที่อาจไม่สามารถให้ค่าที่สมเหตุสมผล ดังนั้นในฟังก์ชั่นของfname
ฉันฉันจะตรวจสอบค่าตอบแทนของdate
เพื่อตรวจสอบความถูกต้องของอินพุตของผู้ใช้:
#!/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"
ดูดี. s.sh
ขอสคริปต์ที่จะตั้งชื่อ หากผู้ใช้เรียกสคริปต์ด้วย./s.sh "Thu Dec 11 20:45:49 CET 2014"
ไฟล์20141211.log
จะถูกสร้างขึ้น อย่างไรก็ตามหากผู้ใช้พิมพ์./s.sh "Thu hec 11 20:45:49 CET 2014"
ดังนั้นสคริปต์จะแสดงผล:
fname reports "Illegal Date"
touch: cannot touch ‘’: No such file or directory
บรรทัดfname…
บอกว่ามีการตรวจพบข้อมูลอินพุตที่ไม่ถูกต้องในเชลล์ย่อย แต่exit 1
ในตอนท้ายของlocal …
เส้นจะไม่เรียกเพราะสั่งเสมอกลับlocal
0
นี่เป็นเพราะlocal
มีการดำเนินการหลังจากนั้น $(fname)
จึงเขียนทับโค้ดส่งคืน และด้วยเหตุนี้สคริปต์จึงดำเนินการต่อและเรียกใช้touch
ด้วยพารามิเตอร์ว่าง ตัวอย่างนี้ง่าย แต่พฤติกรรมของการทุบตีอาจทำให้เกิดความสับสนในการใช้งานจริง ฉันรู้ว่าโปรแกรมเมอร์จริงไม่ใช้คนในท้องถิ่น
เพื่อให้ชัดเจน: หากไม่มีlocal
สคริปต์จะยกเลิกตามที่คาดไว้เมื่อป้อนวันที่ไม่ถูกต้อง
การแก้ไขคือการแบ่งบรรทัดเช่น
local FNAME
FNAME=$(fname "$1") || exit 1
พฤติกรรมแปลก ๆ นั้นสอดคล้องกับเอกสารlocal
ภายในของ man page ของ bash: "สถานะการส่งคืนคือ 0 เว้นแต่ว่า local จะใช้งานนอกฟังก์ชั่นชื่อที่ไม่ถูกต้องจะได้รับหรือชื่อเป็นตัวแปรแบบอ่านอย่างเดียว"
แม้ว่าจะไม่ใช่ข้อผิดพลาด แต่ฉันก็รู้สึกว่าพฤติกรรมของการทุบตีนั้นตรงกันข้าม ฉันตระหนักถึงลำดับของการดำเนินการlocal
ไม่ควรปิดบังการมอบหมายที่ไม่สมบูรณ์อย่างไรก็ตาม
คำตอบแรกของฉันมีบางอย่างที่ไม่ถูกต้อง หลังจากการสนทนาที่เปิดเผยและเจาะลึกกับ mikeserv (ขอบคุณสำหรับสิ่งนั้น) ฉันไปซ่อมมัน