ทำไมไม่ใช้ shebangs ที่ไม่มีเส้นทาง?


24

เป็นไปได้ไหมที่จะมี shebang นั้นแทนที่จะระบุเส้นทางไปยังล่ามมันมีชื่อของล่ามและให้เชลล์ค้นหาผ่าน $ PATH หรือไม่

ถ้าไม่มีเหตุผลทำไม?


คำตอบ:


20

การค้นหาเส้นทางเป็นคุณลักษณะของไลบรารี C มาตรฐานใน userspace เช่นเดียวกับตัวแปรสภาพแวดล้อมโดยทั่วไป เคอร์เนลไม่เห็นตัวแปรสภาพแวดล้อมยกเว้นเมื่อมันผ่านสภาพแวดล้อมจากผู้เรียกexecveไปยังกระบวนการใหม่

เคอร์เนลไม่ได้ทำการตีความใด ๆ บนเส้นทางในexecve(มันขึ้นอยู่กับฟังก์ชั่นการห่อหุ้มเช่นexecvpการค้นหา PATH) หรือใน shebang (ซึ่งมากหรือน้อยเส้นทางการexecveโทรภายใน) ดังนั้นคุณต้องใส่เส้นทางที่แน่นอนในshebang¹ การปรับใช้ Shebang ดั้งเดิมนั้นเป็นโค้ดเพียงไม่กี่บรรทัดและไม่ได้มีการขยายอย่างมีนัยสำคัญตั้งแต่นั้นมา

ใน Unix เวอร์ชันแรกเชลล์ทำหน้าที่เรียกใช้งานตัวเองเมื่อพบว่าคุณกำลังเรียกใช้สคริปต์ Shebang ถูกเพิ่มเข้ามาในเคอร์เนลด้วยเหตุผลหลายประการ (สรุปเหตุผลโดย Dennis Ritchie :

  • ผู้เรียกไม่ต้องกังวลว่าโปรแกรมที่จะดำเนินการเป็นเชลล์สคริปต์หรือไบนารีดั้งเดิม
  • สคริปต์จะระบุสิ่งที่ล่ามที่จะใช้แทนผู้โทร
  • เคอร์เนลใช้ชื่อสคริปต์ในบันทึก

shebangs ที่ไม่มี Path จะต้องเพิ่มเคอร์เนลเพื่อเข้าถึงตัวแปรสภาพแวดล้อมและกระบวนการPATHหรือเพื่อให้เคอร์เนลรันโปรแกรม userspace ที่ทำการค้นหา PATH วิธีแรกต้องเพิ่มจำนวนความซับซ้อนให้กับเคอร์เนล วิธีที่สองคือแล้วเป็นไปได้ด้วยshebang#!/usr/bin/env

¹ หากคุณใส่เส้นทางแบบสัมพัทธ์มันจะแปลความหมายของไดเรกทอรีปัจจุบันของกระบวนการ (ไม่ใช่ไดเรกทอรีที่มีสคริปต์) ซึ่งไม่ค่อยมีประโยชน์ใน Shebang


2
ไม่เคอร์เนลไม่จำเป็นต้องมีพา ธ สัมบูรณ์ในexecveหรือใน shebang แม้ว่าจะมีเหตุผลเล็กน้อยที่จะมีเส้นทางสัมพัทธ์ใน shebang
Stéphane Chazelas

3
สำหรับทุกคนที่สงสัยเกี่ยวกับวิธี "shebang จัดเส้นทางการเรียกการดำเนินการภายใน": จริง ๆ แล้วมันเป็นส่วนหนึ่งของกลไกทั่วไปสำหรับการเรียกใช้ล่ามในไฟล์ปฏิบัติการที่ต้องการ เอลฟ์ที่เชื่อมโยงแบบไดนามิก executables ELF เป็น "ตีความ" โดย/lib64/ld-linux-x86-64.so.2(ดูlddผลลัพธ์) Linux ทำให้เป็นชื่อสามัญอย่างสมบูรณ์: binfmtการสนับสนุน (ตั้งแต่ 2.1.43) ช่วยให้คุณสามารถลงทะเบียนคู่ล่ามพา ธ / พา ธ / หมายเลขมายากลหรือไฟล์นามสกุล คุณสามารถ.exeเรียกใช้PE32 ได้wineเมื่อคุณเรียกใช้คลาส Java และไฟล์ jar เรียกใช้javaฯลฯ
Peter Cordes

#! / usr / bin / env -S [shebang] เป็นสิ่งจำเป็นสำหรับฉันที่ใช้โหนดโดยไม่ทราบเส้นทาง (โดยใช้ nvm - ซึ่งวางไว้ในตำแหน่งที่แตกต่างจากที่ฉันคาดไว้)
TamusJRoyce

-S ใช้ได้เฉพาะตั้งแต่ coreutils 8.30 ดูgitlab.com/gnuwget/wget/commit/… .
Tim Ruehsen rockdaboot

19

มีอะไรเกิดขึ้นมากกว่าสบตา #!บรรทัดถูกตีความโดยเคอร์เนล Unix หรือ Linux #!ไม่ใช่ลักษณะของเชลล์ ซึ่งหมายความว่าPATHไม่มีอยู่จริงในขณะที่เคอร์เนลตัดสินใจว่าจะดำเนินการอะไร

วิธีที่ใช้กันมากที่สุดในการจัดการกับไม่ทราบซึ่งปฏิบัติการเรียกใช้หรือจะเรียกในแฟชั่นแบบพกพาหรือคล้ายกันคือการใช้งานperl #!/usr/bin/env perlเคอร์เนลดำเนินการ/usr/bin/envซึ่งสืบทอดPATHตัวแปรสภาพแวดล้อม envค้นหา (ในตัวอย่างนี้) perlในPATHและใช้การexecve(2)เรียกระบบเพื่อให้เคอร์เนลเรียกใช้perlไฟล์ปฏิบัติการ


4
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0

การแปลงเป็นพา ธ แบบเต็มทำโดยเชลล์ (ทั่วไปมากขึ้น: ใน userspace) เคอร์เนลต้องการชื่อไฟล์ / พา ธ ที่สามารถเข้าถึงได้โดยตรง

หากคุณต้องการให้ระบบค้นหาไฟล์สั่งการของคุณโดยดูผ่านตัวแปร PATH คุณสามารถเขียน shebang ของคุณใหม่#!/usr/bin/env EXECได้

แต่ในกรณีนี้ไม่ใช่เคอร์เนลที่ทำการค้นหา


1
การแปลงเป็นพา ธ แบบเต็มทำได้โดยเชลล์ขอบคุณแม้ว่า ... เป็นตัวอย่างที่ควรจะอธิบายหรือไม่ เท่าที่ฉันเห็นมันเชลล์กำลังทำงานstrace(แปลงเป็น/usr/bin/straceบางจุด) ด้วย 2 อาร์กิวเมนต์
Alois Mahdal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.