เมื่อเชลล์สคริปต์เริ่มต้นด้วย#!บรรทัดแรกนั้นจะเป็นความคิดเห็นเท่าที่เชลล์นั้นเกี่ยวข้อง อย่างไรก็ตามอักขระสองตัวแรกมีความหมายต่อส่วนอื่นของระบบ: เคอร์เนล ตัวละครทั้งสอง#!จะเรียกว่า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