การดำเนินการexitใน subshell เป็นหนึ่งหลุมพราง:
#!/bin/bash
function calc { echo 42; exit 1; }
echo $(calc)
สคริปต์พิมพ์ 42 ออกจากsubshellด้วยโค้ดส่งคืน1และดำเนินการต่อกับสคริปต์ แม้เปลี่ยนการโทรโดยecho $(CALC) || exit 1ไม่ได้ช่วยเพราะการกลับมาของรหัสechoเป็น 0 calcโดยไม่คำนึงถึงรหัสการกลับมาของ และจะดำเนินการไปก่อนcalcecho
ยิ่งทำให้งงงวยก็คือการขัดขวางผลกระทบของการexitห่อไว้ในlocalbuiltin เช่นในสคริปต์ต่อไปนี้ ฉันสะดุดปัญหาเมื่อฉันเขียนฟังก์ชั่นเพื่อตรวจสอบค่าอินพุต ตัวอย่าง:
ฉันต้องการสร้างไฟล์ชื่อ "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 (ขอบคุณสำหรับสิ่งนั้น) ฉันไปซ่อมมัน