ทำไมรูปแบบการทำงานของ `#!` ไม่ได้รับการระบุโดย POSIX


17

จากหน้าภาษาคำสั่งเชลล์ของข้อมูลจำเพาะ POSIX:

หากบรรทัดแรกของไฟล์คำสั่งเชลล์เริ่มต้นด้วยอักขระ "#!" ผลลัพธ์จะไม่ถูกระบุ

ทำไมพฤติกรรมของ#!ไม่ระบุโดย POSIX ฉันพบว่ามันทำให้งงงวยว่าบางสิ่งบางอย่างพกพาและใช้กันอย่างแพร่หลายจะมีพฤติกรรมที่ไม่ระบุ


1
มาตรฐานไม่ได้ระบุสิ่งที่ไม่ผูกติดกับการใช้งานกับพฤติกรรมเฉพาะ ตัวอย่างเช่น "เข้าสู่ระบบ" คือ "กิจกรรมที่ไม่ระบุซึ่งผู้ใช้สามารถเข้าถึงระบบได้"
Kusalananda

2
เนื่องจาก POSIX ไม่ได้ระบุพา ธ ที่สามารถใช้งานได้บรรทัด shebang จึงไม่สามารถพกพาได้ ฉันไม่แน่ใจว่าจะได้รับมากเพียงใดโดยระบุว่าไม่ว่า
Michael Homer

1
@MichaelHomer แน่นอนใช่ไหม มาตรฐานสามารถระบุได้ว่าบรรทัดนั้นมีเส้นทางที่ใช้สำหรับล่ามแม้ว่าจะไม่ได้บอกเส้นทางนั้นว่าควรจะเป็นอะไรก็ตาม
ilkkachu

1
@HaroldFischer ยกเว้นว่าเชลล์ไม่ได้ตีความโดยเชลล์จะตีความโดยเคอร์เนลระบบปฏิบัติการ (ทำอย่างน้อยใน Linux ซึ่งสามารถปิดใช้งานการสนับสนุนนี้ได้ในระหว่างการสร้าง) หรือไลบรารีใดก็ตามที่ใช้exec()ฟังก์ชัน ดังนั้นการตรวจสอบกับหลาย ๆ shells ไม่ได้บอกคุณแบบพกพา
Austin Hemmelgarn

2
@HaroldFischer ยิ่งไปกว่านั้นแม้ว่าใน OS ที่สอดคล้องกับ POSIX พฤติกรรมก็ไม่สอดคล้องกัน Linux และ macOS ทำงานแตกต่างกัน: Linux ไม่โทเค็นบรรทัด Shebang อย่างเต็มที่ตามช่องว่าง macOS ไม่อนุญาตให้ล่ามสคริปต์เป็นสคริปต์อื่น ดูen.wikipedia.org/wiki/Shebang_(Unix)#Portability
jamesdlin

คำตอบ:


21

ฉันคิดว่าเป็นหลักเพราะ:

  • พฤติกรรมที่แตกต่างกันอย่างมากระหว่างการใช้งาน ดูhttps://www.in-ulm.de/~mascheck/various/shebang/สำหรับรายละเอียดทั้งหมด

    อย่างไรก็ตามในตอนนี้มันสามารถระบุเซตย่อยขั้นต่ำของการใช้งาน Unix ที่คล้ายกันมากที่สุดเช่น: #! *[^ ]+( +[^ ]+)?\n(มีเพียงตัวละครจากตัวละครชื่อไฟล์แบบพกพาที่ตั้งอยู่ในหนึ่งหรือสองคำ) ซึ่งคำแรกเป็นเส้นทางที่แน่นอนไปยังปฏิบัติการแบบดั้งเดิม ยาวเกินไปและพฤติกรรมไม่ได้ระบุหากปฏิบัติการได้ setuid / setgid และการใช้งานที่กำหนดว่าเส้นทางล่ามหรือเส้นทางสคริปต์จะถูกส่งผ่านargv[0]ไปยังล่าม

  • POSIX ไม่ได้ระบุเส้นทางของไฟล์ที่เรียกทำงานได้ หลายระบบมียูทิลิตี POSIX ล่วงหน้าใน/bin/ /usr/binและมียูทิลิตี้ POSIX ที่อื่น (เช่นใน Solaris 10 โดยที่/bin/shBourne shell และ POSIX หนึ่งอยู่ใน/usr/xpg4/binนั้น Solaris 11 แทนที่ด้วย ksh93 ซึ่งเป็น POSIX ที่ตรงตามมาตรฐานมากกว่า เครื่องมือใน/binยังคงไม่ใช่ POSIX ที่เก่าแก่) บางระบบไม่ใช่ POSIX แต่มีโหมด / การจำลอง POSIX POSIX ทั้งหมดต้องการคือมีสภาพแวดล้อมที่เป็นเอกสารซึ่งระบบจะทำงานกับ POSIXly

    ดูตัวอย่าง Windows + Cygwin ที่จริงแล้วด้วย Windows + Cygwin She-bang นั้นได้รับเกียรติเมื่อสคริปต์ถูกเรียกใช้โดยแอปพลิเคชั่น cygwin แต่ไม่ใช่โดยแอปพลิเคชัน Windows ดั้งเดิม

    ดังนั้นแม้ว่า POSIX จะระบุกลไก shebang ก็ไม่สามารถใช้ในการเขียนสคริปต์POSIX sh/ sed/ awk... (โปรดทราบว่ากลไก shebang ไม่สามารถใช้ในการเขียนสคริปต์ที่เชื่อถือได้sed/ awkเนื่องจากไม่อนุญาตให้ส่งตัวเลือกปลายทาง เครื่องหมาย)

ตอนนี้ความจริงที่ว่ามันไม่ได้ระบุไม่ได้หมายความว่าคุณไม่สามารถใช้งานได้ (ดีมันบอกว่าคุณไม่ควรเริ่มต้นบรรทัดแรกด้วย#!ถ้าคุณคาดหวังว่ามันจะเป็นเพียงความคิดเห็นปกติและไม่ใช่เธอ - ปัง) แต่ POSIX นั้นไม่รับประกันว่าคุณจะทำอย่างไร

จากประสบการณ์ของฉันการใช้ shebangs ช่วยให้คุณมั่นใจในการพกพาได้มากกว่าการใช้วิธีการเขียนสคริปต์เชลล์ของ POSIX: ออกจาก she-bang เขียนสคริปต์ในshไวยากรณ์POSIX และหวังว่าสิ่งที่เรียกใช้สคริปต์จะเรียกใช้ POSIX shซึ่งเป็น ดีถ้าคุณรู้ว่าสคริปต์จะถูกเรียกใช้ในสภาพแวดล้อมที่เหมาะสมโดยเครื่องมือที่เหมาะสม แต่ไม่เป็นอย่างอื่น

คุณอาจต้องทำสิ่งต่าง ๆ เช่น:

#! /bin/sh -
if : ^ false; then : fine, POSIX system by default
else
  # cover Solaris 10 or older. ": ^ false" returns false
  # in the Bourne shell as ^ is an alias for | there for
  # compatibility with the Thomson shell.
  PATH=`getconf PATH`:$PATH; export PATH
  exec /usr/xpg4/bin/sh - "$0" ${1+"$@"}
fi
# rest of script

หากคุณต้องการที่จะพกพาไปยัง Windows + Cygwin คุณอาจจะต้องตั้งชื่อไฟล์ของคุณด้วย.batหรือ.ps1ส่วนขยายและใช้เคล็ดลับที่คล้ายกันบางอย่างสำหรับการcmd.exeหรือpowershell.exeการเรียก Cygwin shในไฟล์เดียวกัน


ที่น่าสนใจจากปัญหาที่ 5 : "การสร้าง #! ถูกสงวนไว้สำหรับการใช้งานที่ต้องการให้ส่วนขยายนั้นแอปพลิเคชันแบบพกพาไม่สามารถใช้ #! เป็นบรรทัดแรกของเชลล์สคริปต์; อาจไม่ถูกตีความว่าเป็นความคิดเห็น"
muru

@muru ถ้าสคริปต์เป็นแบบพกพาอย่างแท้จริงบนอย่างแท้จริงระบบ POSIX ทำงาน POSIX shก็จะไม่จำเป็นต้องใช้สาย hashbang ที่มันจะได้รับการดำเนินการโดย shPOSIX
Kusalananda

1
@Kusalananda ว่าเป็นความจริงเฉพาะในกรณีที่execlpหรือexecvpถูกนำมาใช้ใช่มั้ย? ถ้าฉันจะใช้execveมันจะส่งผลให้ ENOEXEC?
muru

9

[T] พฤติกรรมของเขาดูเหมือนสอดคล้องกันระหว่างเปลือกร้องเรียน POSIX ทั้งหมด ฉันไม่เห็นความจำเป็นในการห้องกระดิกที่นี่

คุณดูไม่ลึกพอ

ย้อนกลับไปในปี 1980 กลไกนี้ไม่ได้เป็นมาตรฐานอย่างแท้จริง แม้ว่า Dennis Ritchie จะนำไปใช้จริง แต่การนำไปใช้นั้นยังไม่ถึงสาธารณะในด้าน AT&T ของจักรวาล มันมีประสิทธิภาพใช้ได้เฉพาะสาธารณะและเป็นที่รู้จักใน BSD; ที่มีเชลล์สคริปต์ที่เรียกทำงานไม่พร้อมใช้งานบน AT&T Unix ดังนั้นจึงไม่มีเหตุผลที่จะทำให้เป็นมาตรฐาน สถานะของกิจการเป็นสุดขั้วโดย doco ร่วมสมัยนี้หนึ่งในหลาย ๆ เช่น:

โปรดทราบว่า BSD อนุญาตให้เรียกใช้ไฟล์ที่ขึ้นต้นด้วย#! interpreterโดยตรงในขณะที่ SysV อนุญาตให้เรียกใช้ไฟล์ a.out เท่านั้นโดยตรง ซึ่งหมายความว่าอินสแตนซ์ของหนึ่งexec…()ในรูทีนในโปรแกรม BSD อาจจะต้องมีการเปลี่ยนแปลงภายใต้ SysV เพื่อดำเนินการล่าม (typlically /bin/sh) สำหรับโปรแกรมนั้นแทน
- Stephen Frede (1988) "การเขียนโปรแกรมบน System X Release Y" ออสเตรเลีย Unix ระบบกลุ่มผู้ใช้จดหมายข่าว เล่ม 9 หมายเลข 4 หน้า 111

จุดสำคัญที่นี่คือคุณกำลังมองหาเชลล์ในขณะที่การดำรงอยู่ของเชลล์สคริปต์ที่สามารถเรียกใช้งานได้นั้นเป็นเรื่องของexec…()ฟังก์ชั่น สิ่งที่เชลล์ทำรวมถึงสารตั้งต้นของกลไกสคริปต์ที่สามารถเรียกทำงานได้ซึ่งยังคงพบได้ในเชลล์บางตัวในทุกวันนี้ (และในปัจจุบันได้รับคำสั่งสำหรับexec…p()ชุดย่อยของฟังก์ชั่น) และค่อนข้างเข้าใจผิด สิ่งที่ตอบสนองความต้องการมาตรฐานไปยังที่อยู่ในเรื่องนี้เป็นวิธีการexec…()ในการตีความผลงานสคริปต์และในเวลาที่ POSIX ถูกสร้างขึ้นมันก็ไม่ได้ทำงานในสถานที่แรกข้ามเป็นส่วนสำคัญของสเปกตรัมของระบบปฏิบัติการเป้าหมาย

คำถามที่ผู้ใต้บังคับบัญชาคือเหตุผลที่นี้ยังไม่ได้รับมาตรฐานตั้งแต่โดยเฉพาะอย่างยิ่งเป็นกลไกจำนวนมายากลสำหรับล่ามสคริปต์ได้ถึงประชาชนใน AT & T ด้านข้างของจักรวาลและได้รับการรับรองสำหรับexec…()ในความหมายของระบบ 5 การเชื่อมต่อโดยการหันของปี 1990 :

ไฟล์ล่ามเริ่มต้นด้วยบรรทัดของแบบฟอร์ม

#! ชื่อพา ธ [หาเรื่อง]
โดยที่pathnameคือเส้นทางของล่ามและหาเรื่องเป็นอาร์กิวเมนต์ที่เป็นทางเลือก เมื่อคุณexecเป็นไฟล์ล่ามระบบexecจะเป็นล่ามที่ระบุ
exec- ระบบวีอินเตอร์เฟซนิยาม เล่มที่ 1 1991

แต่น่าเสียดายที่พฤติกรรมยังคงอยู่ในปัจจุบันเกือบจะแตกต่างกันอย่างกว้างขวางเหมือนในปี 1980 และไม่มีพฤติกรรมทั่วไปที่จะสร้างมาตรฐาน บาง Unices (ตัวอย่างเช่น HP-UX และ FreeBSD ที่มีชื่อเสียง) ไม่สนับสนุนสคริปต์ในฐานะล่ามสำหรับสคริปต์ ไม่ว่าบรรทัดแรกจะเป็นหนึ่งสองหรือหลายองค์ประกอบที่คั่นด้วยช่องว่างจะแตกต่างกันระหว่าง MacOS (และ FreeBSD เวอร์ชันก่อนปี 2005) และอื่น ๆ ความยาวพา ธ สูงสุดที่รองรับแตกต่างกันไป และตัวละครที่อยู่เหนือชุดอักขระชื่อไฟล์แบบพกพา POSIX นั้นมีความยุ่งยากเช่นเดียวกับช่องว่างชั้นนำและต่อท้าย สิ่งที่อาร์กิวเมนต์อันดับที่ 1, 1 และที่ 2 นั้นจบลงด้วยความยากลำบากโดยมีการเปลี่ยนแปลงที่สำคัญในระบบต่างๆ บางอย่างสอดคล้องกับ POSIX ปัจจุบัน แต่ไม่ใช่- ระบบ Unix ยังไม่สนับสนุนกลไกดังกล่าวและการบังคับให้แปลงเป็น POSIX ไม่ได้อีกต่อไป

อ่านเพิ่มเติม


1

ตามที่ระบุไว้โดยบางส่วนของคำตอบอื่น ๆ การใช้งานแตกต่างกันไป สิ่งนี้ทำให้ยากที่จะสร้างมาตรฐานและรักษาความเข้ากันได้ย้อนหลังกับสคริปต์ที่มีอยู่ สิ่งนี้เป็นจริงแม้สำหรับระบบ POSIX ที่ทันสมัย ยกตัวอย่างเช่นลีนุกซ์ไม่ได้เติมโทเค็นไลน์ด้วยช่องว่างอย่างเต็มที่ macOS ไม่อนุญาตให้ล่ามสคริปต์เป็นสคริปต์อื่น

ดูhttp://en.wikipedia.org/wiki/Shebang_(Unix)#Portability

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.