#! / bin / sh -
(หรืออย่างน้อยเป็น) มักจะแนะนำshebang/bin/shจะมีสคริปต์ตีความโดย
ทำไมไม่เพียง#! /bin/shหรือ#!/bin/sh?
มีอะไรที่-หา?
#! / bin / sh -
(หรืออย่างน้อยเป็น) มักจะแนะนำshebang/bin/shจะมีสคริปต์ตีความโดย
ทำไมไม่เพียง#! /bin/shหรือ#!/bin/sh?
มีอะไรที่-หา?
คำตอบ:
นั่นเป็นเหตุผลที่คล้ายกันว่าทำไมคุณต้องเขียน:
rm -- *.txt
และไม่
rm *.txt
ถ้าคุณสามารถรับประกันไม่มีไฟล์ในไดเรกทอรีปัจจุบันมีชื่อที่ขึ้นต้นด้วย.txt-
ใน:
rm <arg>
<arg>ถือเป็นตัวเลือกถ้ามันเริ่มต้นด้วย-หรือไฟล์ที่จะลบอย่างอื่น ใน
rm - <arg>
argถูกพิจารณาว่าเป็นไฟล์ที่จะลบโดยไม่คำนึงว่าไฟล์นั้นขึ้นต้นด้วย-หรือไม่
shนั่นเป็นเหมือนกันสำหรับ
เมื่อหนึ่งรันสคริปต์ที่เริ่มต้นด้วย
#! /bin/sh
โดยทั่วไปด้วย:
execve("path/to/the-script", ["the-script", "arg"], [environ])
ระบบเปลี่ยนเป็น:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
path/to/the-scriptไม่ปกติบางสิ่งบางอย่างที่อยู่ภายใต้การควบคุมของผู้เขียนสคริปต์ ผู้เขียนไม่สามารถคาดเดาได้ว่าจะเก็บสำเนาของสคริปต์ไว้ที่ใดหรือภายใต้ชื่อใด โดยเฉพาะอย่างยิ่งพวกเขาไม่สามารถรับประกันได้ว่าสิ่งpath/to/the-scriptที่เรียกว่าจะไม่เริ่มต้นด้วย-(หรือ+ที่เป็นปัญหาด้วยsh) นั่นเป็นเหตุผลที่เราต้องการที่-นี่เพื่อทำเครื่องหมายจุดสิ้นสุดของตัวเลือก
ตัวอย่างเช่นในระบบของฉันzcat(เหมือนจริง ๆ กับสคริปต์อื่น ๆ ) เป็นตัวอย่างหนึ่งของสคริปต์ที่ไม่ปฏิบัติตามคำแนะนำนั้น:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
ตอนนี้คุณอาจถามว่าทำไม#! /bin/sh -และไม่#! /bin/sh --?
แม้ว่า#! /bin/sh --จะทำงานกับ POSIX เชลล์ได้ แต่#! /bin/sh -ก็พกพาได้มากกว่า shโดยเฉพาะอย่างยิ่งกับรุ่นโบราณ shการปฏิบัติ-เป็นและสิ้นสุดของตัวเลือกถือกำเนิดgetopt()และการใช้งานทั่วไปของ--เพื่อทำเครื่องหมายจุดสิ้นสุดของตัวเลือกโดยใช้เวลานาน วิธีที่บอร์นเชลล์ (จากปลายยุค 70) -แยกวิเคราะห์อาร์กิวเมนต์เท่านั้นอาร์กิวเมนต์แรกที่ได้รับการพิจารณาให้เป็นตัวเลือกถ้ามันเริ่มต้นด้วย อักขระทั้งหมดหลังจากนั้น-จะถือว่าเป็นชื่อตัวเลือก หากไม่มีตัวละครหลังจาก-นั้นก็ไม่มีตัวเลือก สิ่งนั้นติดอยู่และเชลล์ที่เหมือนบอร์นในภายหลังทั้งหมดรู้จัก-เป็นวิธีการทำเครื่องหมายจุดสิ้นสุดของตัวเลือก
ในเชลล์เป้าหมาย (แต่ไม่ใช่ในเชลล์บอร์นที่ทันสมัย) #! /bin/sh -eufจะแก้ไขปัญหาได้เนื่องจากอาร์กิวเมนต์แรกเท่านั้นที่ถูกพิจารณาเป็นตัวเลือก
ทีนี้ใคร ๆ ก็บอกได้ว่าเราเป็นคนอวดดีที่นี่และมันก็เป็นเหตุผลที่ฉันเขียนความต้องการเป็นตัวเอียงด้านบน:
-หรือ+หรือใส่ไว้ในไดเรกทอรีที่มีชื่อขึ้นต้นด้วยหรือ-+execvp()/ execlp()- ประเภท และในกรณีนั้นโดยทั่วไปคุณเรียกใช้the-scriptมันเพื่อค้นหา$PATHในกรณีที่อาร์กิวเมนต์เส้นทางไปยังการexecve()เรียกระบบโดยทั่วไปจะเริ่มต้นด้วย/(ไม่ใช่-หรือ+) หรือราวกับ./the-scriptว่าคุณต้องการthe-scriptให้เรียกใช้ไดเรกทอรีปัจจุบัน (และ จากนั้นพา ธ เริ่มต้นด้วย./ไม่ใช่-หรือ+อย่างใดอย่างหนึ่ง)ตอนนี้ข้างทางทฤษฎีถูกต้องปัญหามีเหตุผลว่าทำไมอีก#! /bin/sh -กลายเป็นที่แนะนำเป็นวิธีปฏิบัติที่ดี และนั่นกลับไปเป็นช่วงเวลาที่หลาย ๆ ระบบยังคงรองรับสคริปต์ setuid
หากคุณมีสคริปต์ที่มี:
#! /bin/sh
/bin/echo "I'm running as root"
และสคริปต์นั้นคือรูท setuid (เช่นมี-r-sr-xr-x root binสิทธิ์) บนระบบเหล่านั้นเมื่อผู้ใช้ทั่วไปเรียกใช้
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
จะทำตามroot!
หากผู้ใช้สร้างลิงก์สัญลักษณ์/tmp/-i -> path/to/the-scriptและดำเนินการเป็น-iแล้วมันจะเริ่มต้นเปลือกโต้ตอบ ( /bin/sh -i) rootในฐานะ
-ที่จะทำงานรอบที่ (มันจะไม่ทำงานรอบปัญหาการแข่งขันสภาพหรือความจริงที่ว่าบางshการใช้งานเช่นบางksh88คนจะชั่นค้นหาข้อโต้แย้งโดยไม่ต้องสคริปต์/ใน$PATHแม้ว่า)
ปัจจุบันแทบจะทุกระบบสนับสนุนสคริปต์ setuid อีกต่อไปและบางส่วนที่ยังคงทำอยู่ (โดยปกติจะไม่เป็นค่าเริ่มต้น) จบลงด้วยการทำexecve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])(ซึ่ง<n>เป็นไฟล์อธิบายเปิดให้อ่านสคริปต์) ซึ่งทำงานทั้งปัญหานี้และ สภาพการแข่งขัน.
โปรดทราบว่าคุณได้รับปัญหาที่คล้ายกันกับล่ามส่วนใหญ่ไม่เพียง แต่เปลือกหอย Bourne โดยทั่วไปเชลล์ที่ไม่คล้ายบอร์นไม่ได้รับการสนับสนุน-ในฐานะเครื่องหมายสิ้นสุดของตัวเลือก แต่โดยทั่วไปแล้วจะรองรับ--แทน (อย่างน้อยสำหรับเวอร์ชันที่ทันสมัย)
ด้วย
#! /usr/bin/awk -f
#! /usr/bin/sed -f
ไม่มีปัญหาเนื่องจากอาร์กิวเมนต์ถัดไปถือเป็นอาร์กิวเมนต์ของ-fตัวเลือกในทุกกรณี แต่ก็ยังใช้งานไม่ได้หากpath/to/scriptเป็น-(ในกรณีนี้โดยส่วนใหญ่sed/ awkการใช้งานsed/ awkไม่อ่านโค้ดจาก-ไฟล์ แต่มาจาก stdin แทน)
โปรดทราบว่าในระบบส่วนใหญ่ระบบหนึ่งไม่สามารถใช้:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
ในระบบส่วนใหญ่กลไก shebang อนุญาตการโต้แย้งเพียงครั้งเดียวหลังจากเส้นทางล่าม
ว่าจะใช้#! /bin/sh -vs #!/bin/sh -หรือไม่นั่นเป็นเพียงเรื่องของรสนิยม ฉันชอบแบบดั้งเดิมเนื่องจากทำให้เส้นทางล่ามมองเห็นได้ชัดเจนขึ้นและทำให้การเลือกเมาส์ง่ายขึ้น มีตำนานกล่าวว่าจำเป็นต้องใช้พื้นที่ใน Unix บางรุ่นแต่เป็น AFAIK ซึ่งไม่เคยมีการยืนยัน
การอ้างอิงที่ดีมากเกี่ยวกับ Unix shebang สามารถดูได้ที่https://www.in-ulm.de/~mascheck/various/shebang
bashยอมรับตัวเลือกเช่นเปลือกอื่น ๆ เป็นบอร์นเหมือนและ POSIX เปลือกbashยอมรับทั้งในและ#! /bin/bash - #! /bin/bash --