เมื่อเชลล์สคริปต์เริ่มต้นด้วย#!
บรรทัดแรกนั้นจะเป็นความคิดเห็นเท่าที่เชลล์นั้นเกี่ยวข้อง อย่างไรก็ตามอักขระสองตัวแรกมีความหมายต่อส่วนอื่นของระบบ: เคอร์เนล ตัวละครทั้งสอง#!
จะเรียกว่าshebang เพื่อให้เข้าใจบทบาทของ shebang คุณต้องเข้าใจวิธีการใช้งานโปรแกรม
การเรียกใช้งานโปรแกรมจากไฟล์ต้องการการดำเนินการจากเคอร์เนล นี่เป็นส่วนหนึ่งของการexecve
เรียกระบบ เคอร์เนลจำเป็นต้องตรวจสอบการอนุญาตของไฟล์ปลดปล่อยทรัพยากร (หน่วยความจำและอื่น ๆ ) ที่เกี่ยวข้องกับไฟล์ปฏิบัติการที่กำลังทำงานในกระบวนการเรียกจัดสรรทรัพยากรสำหรับไฟล์ปฏิบัติการใหม่และโอนการควบคุมไปยังโปรแกรมใหม่ (และสิ่งอื่น ๆ อีกมากมายที่ ฉันจะไม่พูดถึง) การexecve
เรียกระบบแทนที่รหัสของกระบวนการที่กำลังทำงานอยู่ มีการเรียกระบบแยกจากกันfork
เพื่อสร้างกระบวนการใหม่
ในการดำเนินการนี้เคอร์เนลจะต้องสนับสนุนรูปแบบของไฟล์ที่ปฏิบัติการได้ ไฟล์นี้จะต้องมีรหัสเครื่องจัดระเบียบในลักษณะที่เคอร์เนลเข้าใจ เชลล์สคริปต์ไม่มีรหัสเครื่องดังนั้นจึงไม่สามารถเรียกใช้งานด้วยวิธีนี้ได้
กลไก shebang ช่วยให้เคอร์เนลเลื่อนงานของการตีความรหัสไปยังโปรแกรมอื่น เมื่อเคอร์เนลเห็นว่าไฟล์เรียกทำงานเริ่มต้นด้วย#!
มันจะอ่านตัวละครสองสามตัวถัดไปและตีความบรรทัดแรกของไฟล์ (ลบด้วย#!
พื้นที่ว่างนำหน้าและทางเลือก) เป็นพา ธ ไปยังไฟล์อื่น (บวกอาร์กิวเมนต์ที่ฉันจะไม่พูดถึงที่นี่ ) เมื่อเคอร์เนลจะบอกให้เรียกใช้ไฟล์/my/script
และจะเห็นว่าไฟล์เริ่มต้นด้วยสาย#!/some/interpreter
เคอร์เนลดำเนินการกับการโต้แย้ง/some/interpreter
/my/script
มันขึ้นอยู่กับ/some/interpreter
การตัดสินใจว่า/my/script
เป็นไฟล์สคริปต์ที่ควรดำเนินการ
จะเกิดอะไรขึ้นถ้าไฟล์ไม่มีรหัสเนทีฟในรูปแบบที่เคอร์เนลเข้าใจและไม่เริ่มต้นด้วย shebang ถ้าอย่างนั้นไฟล์ไม่สามารถเรียกใช้งานได้และการexecve
เรียกระบบล้มเหลวพร้อมรหัสENOEXEC
ข้อผิดพลาด
นี่อาจเป็นจุดสิ้นสุดของเรื่องราว แต่กระสุนส่วนใหญ่ใช้คุณสมบัติทางเลือก หากเคอร์เนลส่งคืนENOEXEC
เชลล์จะพิจารณาเนื้อหาของไฟล์และตรวจสอบว่าดูเหมือนเชลล์สคริปต์หรือไม่ หากเชลล์คิดว่าไฟล์ดูเหมือนว่าเชลล์สคริปต์จะดำเนินการด้วยตัวเอง รายละเอียดของสิ่งนี้มันขึ้นอยู่กับเปลือก คุณสามารถเห็นสิ่งที่เกิดขึ้นโดยการเพิ่มps $$
สคริปต์ของคุณและอื่น ๆ โดยการดูกระบวนการstrace -p1234 -f -eprocess
ที่ 1234 เป็น PID ของเชลล์
ในทุบตีกลไกทางเลือกนี้จะดำเนินการโดยการเรียกแต่ไม่fork
execve
กระบวนการทุบตีเด็กล้างสถานะภายในของตัวเองและเปิดไฟล์สคริปต์ใหม่เพื่อเรียกใช้ ดังนั้นกระบวนการที่เรียกใช้สคริปต์ยังคงใช้อิมเมจรหัส bash ดั้งเดิมและอาร์กิวเมนต์บรรทัดคำสั่งดั้งเดิมที่ส่งผ่านเมื่อคุณเรียกใช้งาน bash ในตอนแรก ATT ksh ทำงานในลักษณะเดียวกัน
% bash --norc
bash-4.3$ ./foo.sh
PID TTY STAT TIME COMMAND
21913 pts/2 S+ 0:00 bash --norc
ในทางตรงกันข้าม Dash ตอบสนองENOEXEC
โดยการเรียก/bin/sh
ด้วยพา ธ ไปยังสคริปต์ที่ส่งเป็นอาร์กิวเมนต์ ในคำอื่น ๆ เมื่อคุณรันสคริปต์ shebangless จากประมันจะทำงานเช่นถ้าสคริปต์ที่มีเส้น shebang #!/bin/sh
กับ Mksh และ zsh ทำงานในลักษณะเดียวกัน
% dash
$ ./foo.sh
PID TTY STAT TIME COMMAND
21427 pts/2 S+ 0:00 /bin/sh ./foo.sh