ในการเขียนโปรแกรมจำเป็นทั่วไปคุณเขียนลำดับของคำสั่งและพวกเขาจะดำเนินการหนึ่งหลังจากที่อื่น ๆ ที่มีการไหลของการควบคุมที่ชัดเจน ตัวอย่างเช่น:
if [ -f file1 ]; then # If file1 exists ...
cp file1 file2 # ... create file2 as a copy of a file1
fi
เป็นต้น
ดังที่สามารถเห็นได้จากตัวอย่างในการเขียนโปรแกรมที่จำเป็นคุณติดตามการไหลของการดำเนินการค่อนข้างง่ายเสมอทำงานของคุณขึ้นมาจากบรรทัดของรหัสใด ๆ ที่กำหนดเพื่อกำหนดบริบทการดำเนินการโดยรู้ว่าคำสั่งใด ๆ ที่คุณให้จะถูกดำเนินการ ตำแหน่งในโฟลว์ (หรือตำแหน่งของไซต์การโทรหากคุณกำลังเขียนฟังก์ชัน)
วิธีการเรียกกลับเปลี่ยนกระแส
เมื่อคุณใช้การเรียกกลับแทนที่จะวางชุดคำแนะนำ "ทางภูมิศาสตร์" คุณจะอธิบายเมื่อควรเรียกใช้ ตัวอย่างทั่วไปในสภาพแวดล้อมการเขียนโปรแกรมอื่น ๆ เป็นกรณีเช่น "ดาวน์โหลดทรัพยากรนี้และเมื่อการดาวน์โหลดเสร็จสมบูรณ์แล้วให้เรียกใช้การเรียกกลับนี้" Bash ไม่มีโครงสร้างการเรียกกลับแบบทั่วไป แต่มีการเรียกกลับสำหรับการจัดการข้อผิดพลาดและสถานการณ์อื่น ๆ ตัวอย่างเช่น (ก่อนอื่นต้องเข้าใจการแทนที่คำสั่งและโหมด Bash exit ก่อนเพื่อทำความเข้าใจตัวอย่างนั้น):
#!/bin/bash
scripttmp=$(mktemp -d) # Create a temporary directory (these will usually be created under /tmp or /var/tmp/)
cleanup() { # Declare a cleanup function
rm -rf "${scripttmp}" # ... which deletes the temporary directory we just created
}
trap cleanup EXIT # Ask Bash to call cleanup on exit
หากคุณต้องการลองด้วยตัวคุณเองให้บันทึกข้างต้นลงในไฟล์โดยบอกว่าcleanUpOnExit.sh
ทำให้มันใช้งานได้และเรียกใช้:
chmod 755 cleanUpOnExit.sh
./cleanUpOnExit.sh
รหัสของฉันที่นี่ไม่เคยเรียกcleanup
ฟังก์ชั่นอย่างชัดเจน; มันบอกทุบตีเมื่อจะเรียกมันว่าใช้trap cleanup EXIT
, เช่น “รักทุบตีโปรดเรียกใช้cleanup
คำสั่งเมื่อคุณออก” (และcleanup
เกิดขึ้นเป็นฟังก์ชั่นที่กำหนดไว้ก่อนหน้านี้ผม แต่มันจะเป็นอะไรทุบตีเข้าใจ) Bash รองรับสิ่งนี้สำหรับสัญญาณที่ไม่ร้ายแรง, ออก, ความล้มเหลวของคำสั่งและการดีบักทั่วไป (คุณสามารถระบุการเรียกกลับที่ทำงานก่อนทุกคำสั่ง) การเรียกกลับที่นี่คือcleanup
ฟังก์ชั่นซึ่งเป็น“ เรียกกลับ” โดย Bash ก่อนที่เชลล์จะออก
คุณสามารถใช้ความสามารถของ Bash ในการประเมินพารามิเตอร์ของเชลล์เป็นคำสั่งเพื่อสร้างเฟรมเวิร์กที่มุ่งเน้นการติดต่อกลับ ที่ค่อนข้างเกินขอบเขตของคำตอบนี้และอาจทำให้เกิดความสับสนมากขึ้นโดยแนะนำให้ฟังก์ชั่นที่ผ่านรอบที่เกี่ยวข้องกับการโทรกลับ ดูBash: ผ่านฟังก์ชั่นเป็นพารามิเตอร์สำหรับตัวอย่างของฟังก์ชั่นพื้นฐาน แนวคิดที่นี่เช่นเดียวกับการเรียกกลับจัดการเหตุการณ์คือฟังก์ชั่นสามารถใช้ข้อมูลเป็นพารามิเตอร์ แต่ยังฟังก์ชั่นอื่น ๆ - นี้ช่วยให้ผู้โทรสามารถให้พฤติกรรมเช่นเดียวกับข้อมูล ตัวอย่างง่ายๆของวิธีการนี้อาจดูเหมือน
#!/bin/bash
doonall() {
command="$1"
shift
for arg; do
"${command}" "${arg}"
done
}
backup() {
mkdir -p ~/backup
cp "$1" ~/backup
}
doonall backup "$@"
(ฉันรู้ว่านี่มันไร้ประโยชน์นิดหน่อยเพราะcp
สามารถจัดการกับไฟล์หลาย ๆ ไฟล์มันเป็นเพียงภาพประกอบเท่านั้น)
ที่นี่เราสร้างฟังก์ชั่นdoonall
ซึ่งใช้คำสั่งอื่นให้เป็นพารามิเตอร์และนำไปใช้กับส่วนที่เหลือของพารามิเตอร์ จากนั้นเราจะใช้backup
ฟังก์ชันนี้เพื่อเรียกใช้ฟังก์ชันกับพารามิเตอร์ทั้งหมดที่กำหนดให้กับสคริปต์ ผลลัพธ์คือสคริปต์ที่คัดลอกอาร์กิวเมนต์ทั้งหมดทีละหนึ่งไปยังไดเร็กทอรีสำรอง
วิธีการแบบนี้ช่วยให้ฟังก์ชั่นสามารถเขียนด้วยความรับผิดชอบเดียว: doonall
ความรับผิดชอบของคือการเรียกใช้บางสิ่งบางอย่างในทุกข้อโต้แย้งของมันทีละครั้ง; backup
ความรับผิดชอบของคือการทำสำเนาของอาร์กิวเมนต์ (แต่เพียงผู้เดียว) ในไดเรกทอรีสำรอง ทั้งสองdoonall
และbackup
สามารถใช้ในบริบทอื่น ๆ ซึ่งอนุญาตให้ใช้รหัสได้มากขึ้นการทดสอบที่ดีขึ้น ฯลฯ
ในกรณีนี้การเรียกกลับเป็นbackup
ฟังก์ชั่นซึ่งเราบอกdoonall
ให้ "โทรกลับ" ในแต่ละข้อโต้แย้งอื่น ๆ ของมัน - เราให้doonall
กับพฤติกรรม (อาร์กิวเมนต์แรกของมัน) เช่นเดียวกับข้อมูล (อาร์กิวเมนต์ที่เหลือ)
(โปรดทราบว่าในรูปแบบการใช้งานที่แสดงในตัวอย่างที่สองฉันจะไม่ใช้คำว่า "โทรกลับ" ด้วยตัวเอง แต่นั่นอาจเป็นนิสัยที่เกิดจากภาษาที่ฉันใช้ฉันคิดว่านี่เป็นหน้าที่ส่งผ่านหรือ lambdas รอบ ๆ แทนที่จะลงทะเบียนการเรียกกลับในระบบเชิงเหตุการณ์)