ในbash
หรือsh
ผมคิดว่าอะไรที่เริ่มต้นด้วยการ#
เป็นความคิดเห็น
แต่ในbash
สคริปต์เราเขียน:
#!/bin/bash
และในสคริปต์ Python มี:
#!/bin/python
นี่หมายความว่า#
โดยตัวของมันเองเป็นความคิดเห็นในขณะที่#!
ไม่ได้เป็น?
ในbash
หรือsh
ผมคิดว่าอะไรที่เริ่มต้นด้วยการ#
เป็นความคิดเห็น
แต่ในbash
สคริปต์เราเขียน:
#!/bin/bash
และในสคริปต์ Python มี:
#!/bin/python
นี่หมายความว่า#
โดยตัวของมันเองเป็นความคิดเห็นในขณะที่#!
ไม่ได้เป็น?
คำตอบ:
#!
บรรทัดใช้ก่อนสคริปต์ที่จะดำเนินการไม่สนใจแล้วเมื่อสคริปต์คุณกำลังถามว่าความแตกต่างระหว่างเส้น Shebangกับความคิดเห็นทั่วไปคืออะไร
บรรทัดที่เริ่มต้นด้วยการ#!
เป็นเพียงเท่าแสดงความคิดเห็นเป็นสายอื่น ๆ #
ที่เริ่มต้นด้วย กรณีนี้เป็นจริงถ้า#!
บรรทัดแรกของไฟล์หรือที่อื่น ๆ #!/bin/sh
มีผลกระทบแต่มันก็ไม่ได้อ่านโดยล่ามของตัวเอง
#
ไม่ใช่ความคิดเห็นในภาษาการเขียนโปรแกรมทั้งหมด แต่อย่างที่คุณทราบมันเป็นความคิดเห็นในเชลล์สไตล์ Bourne ซึ่งรวมถึงsh
และbash
( รวมถึงเชลล์ที่ไม่ใช่บอร์นแบบส่วนใหญ่เช่นcsh
) มันยังมีความคิดเห็นในหลาม และมันเป็นความคิดเห็นในไฟล์การกำหนดค่าที่หลากหลายซึ่งไม่ใช่สคริปต์จริงๆ (เหมือน/etc/fstab
)
#!/bin/sh
สมมติว่าเชลล์สคริปต์เริ่มต้นด้วย นั่นคือความคิดเห็นและล่าม (เปลือก) จะไม่สนใจทุกสิ่งในบรรทัดถัดจาก#
อักขระ
จุดประสงค์ของ#!
สายไม่ให้ข้อมูลกับล่าม วัตถุประสงค์ของ#!
เส้นคือการบอกระบบปฏิบัติการ (หรือกระบวนการสิ่งที่เปิดตัวล่าม) สิ่งที่จะใช้เป็นล่าม
หากคุณเรียกใช้สคริปต์เป็นไฟล์เรียกทำงานตัวอย่างเช่นโดยการรัน./script.sh
ระบบจะพิจารณาบรรทัดแรกเพื่อดูว่าเริ่มต้นด้วย#!
ตามด้วยศูนย์หรือมากกว่าเว้นวรรคตามด้วยคำสั่ง หากเป็นเช่นนั้นคำสั่งนั้นจะรันพร้อมชื่อของสคริปต์เป็นอาร์กิวเมนต์ ในตัวอย่างนี้มันทำงาน/bin/sh script.sh
(หรือในทางเทคนิค/bin/sh ./script.sh
)
หากคุณเรียกใช้สคริปต์โดยการเรียกล่ามอย่างชัดเจน#!
จะไม่มีการปรึกษาสาย ดังนั้นหากคุณเรียกใช้sh script.sh
บรรทัดแรกจะไม่มีผลใด ๆ หากscript2.sh
บรรทัดแรกคือการ#!/usr/games/nibbles
ทำงานsh script2.sh
จะไม่พยายามเปิดสคริปต์ในnibbles
(แต่./script2.sh
จะ)
คุณจะสังเกตเห็นว่าไม่ว่าในกรณีใดส่วนขยายของสคริปต์ ( .sh
) ถ้ามีจะมีผลกระทบต่อการทำงานของสคริปต์ ในระบบที่คล้าย Unix สิ่งนี้จะไม่ส่งผลกระทบต่อวิธีการเรียกใช้สคริปต์ ในบางระบบเช่น Windows #!
บรรทัด shebang อาจถูกละเว้นโดยระบบและส่วนขยายอาจเป็นตัวกำหนดว่าจะเรียกใช้สคริปต์อย่างไร (นี่ไม่ได้หมายความว่าคุณต้องให้ส่วนขยายสคริปต์ของคุณ แต่นี่เป็นหนึ่งในสาเหตุที่ทำให้คุณต้องแก้ไขให้ถูกต้อง)
#!
ได้รับเลือกให้ตอบสนองวัตถุประสงค์นี้อย่างแม่นยำเพราะ #
เริ่มแสดงความคิดเห็น #!
สายสำหรับระบบที่ไม่ได้ล่ามและมันควรจะละเว้นโดยล่าม
คุณ (เดิม) กล่าวว่าคุณใช้#!/bin/sh
สำหรับbash
สคริปต์ คุณควรทำเช่นนั้นหากสคริปต์ไม่ต้องการbash
ส่วนขยายใด ๆ- sh
จะต้องสามารถเรียกใช้สคริปต์ได้ sh
ไม่เคย symlink bash
ไป มักจะรวมถึงในทุกระยะไกลล่าสุด Debian และ Ubuntu ระบบ , sh
เป็น symlink dash
ไป
นอกจากนี้คุณยังกล่าวว่า (ในรุ่นแรกของคำถามของคุณก่อนที่จะแก้ไข) #!/bin/sh read by the interpretor
ที่คุณเริ่มต้นงูหลามสคริปต์ของคุณด้วย หากคุณหมายถึงอย่างแท้จริงคุณควรหยุดทำอย่างนั้น หากhello.py
เริ่มต้นด้วยบรรทัดนั้นการ./hello.py
รันจะดำเนินการ:
/bin/sh read by the interpretor hello.py
/bin/sh
จะพยายามเรียกใช้งานสคริปต์ที่เรียกว่าread
(โดยใช้by the interpretor hello.py
เป็นอาร์กิวเมนต์) read
จะ (หวังว่า) จะไม่พบและสคริปต์ Python ของคุณจะไม่ถูกมองเห็นโดยล่าม Python
หากคุณทำผิดพลาด แต่ไม่พบปัญหาที่ฉันอธิบายคุณอาจเรียกใช้ Scrips Python ของคุณโดยระบุล่าม (เช่นpython hello.py
) ทำให้เกิดการละเว้นบรรทัดแรก เมื่อคุณแจกจ่ายสคริปต์ของคุณให้ผู้อื่นหรือใช้ในภายหลังในภายหลังอาจไม่ชัดเจนว่านี่เป็นสิ่งจำเป็นสำหรับพวกเขาในการทำงาน เป็นการดีที่สุดที่จะแก้ไขพวกเขาตอนนี้ หรืออย่างน้อยลบบรรทัดแรกทั้งหมดเพื่อว่าเมื่อพวกเขาล้มเหลวในการทำงานด้วย./
ข้อความแสดงข้อผิดพลาดจะทำให้รู้สึก
สำหรับสคริปต์ Python ถ้าคุณรู้ว่าตัวแปล Python อยู่ที่ไหน (หรือจะเป็น) คุณสามารถเขียน#!
บรรทัดได้ในลักษณะเดียวกัน:
#!/usr/bin/python
หรือถ้าเป็นสคริปต์ Python 3 คุณควรระบุpython3
เนื่องจากpython
เกือบจะเป็น Python 2 เสมอ :
#!/usr/bin/python3
อย่างไรก็ตามปัญหาคือในขณะที่/bin/sh
ควรจะมีอยู่เสมอและ/bin/bash
เกือบจะมีอยู่ในระบบที่bash
มาพร้อมกับระบบปฏิบัติการ Python อาจมีอยู่ในหลายสถานที่
ดังนั้นโปรแกรมเมอร์ Python หลายคนใช้สิ่งนี้แทน:
#!/usr/bin/env python
(หรือ#!/usr/bin/env python3
สำหรับ Python 3)
สิ่งนี้ทำให้สคริปต์พึ่งพาenv
การอยู่ใน "สถานที่ที่เหมาะสม" แทนที่จะอาศัยอยู่python
ในสถานที่ที่เหมาะสม นั่นเป็นสิ่งที่ดีเพราะ:
env
/usr/bin
เกือบจะอยู่เสมอในpython
ควรPATH
เรียกใช้สคริปต์ของคุณเป็นหนึ่งที่ปรากฏขึ้นครั้งแรกในปีนี้ เริ่มต้นhello.py
ด้วยการ#!/usr/bin/env python
ทำให้./hello.py
การทำงาน/usr/bin/env python hello.py
ซึ่งเป็น (แทบ) python hello.py
เทียบเท่ากับการทำงานเหตุผลที่คุณไม่สามารถใช้#!python
คือ:
/
)python
การค้นหาพา ธ เมื่อคำสั่งไม่มีเครื่องหมายทับเป็นลักษณะการทำงานของเชลล์เฉพาะบางครั้งหลามหรือสคริปต์อื่น ๆ ที่ไม่ได้เป็นสคริปต์เปลือกจะมีสาย shebang ที่เริ่มต้นด้วย#!/bin/sh ...
ที่...
บางรหัสอื่น ๆ บางครั้งสิ่งนี้ถูกต้องเพราะมีบางวิธีในการเรียกใช้เชลล์ที่เข้ากันได้กับ Bourne ( sh
) พร้อมกับอาร์กิวเมนต์เพื่อเรียกใช้ตัวแปลภาษา Python (อาจมีหนึ่งในข้อโต้แย้งpython
) อย่างไรก็ตามสำหรับจุดประสงค์ส่วนใหญ่#!/usr/bin/env python
เรียบง่ายสง่างามและมีแนวโน้มที่จะทำงานในแบบที่คุณต้องการ
ภาษาการเขียนโปรแกรมและสคริปต์จำนวนมากและรูปแบบไฟล์อื่น ๆ ใช้#
เป็นความคิดเห็น สำหรับการใด ๆ ของพวกเขา, #!
ไฟล์ในภาษาที่สามารถดำเนินการโดยโปรแกรมที่ใช้มันเป็นอาร์กิวเมนต์โดยระบุโปรแกรมบนบรรทัดแรกหลังจาก
ในบางภาษาการเขียนโปรแกรม#
เป็นปกติไม่แสดงความคิดเห็น #!
แต่เป็นกรณีพิเศษบรรทัดแรกจะถูกละเว้นถ้ามันเริ่มต้นด้วย สิ่งนี้จะช่วยให้การใช้#!
ไวยากรณ์ง่ายขึ้นแม้ว่าจะ#
ไม่ได้ให้ความคิดเห็นก็ตาม
ในขณะที่มันใช้งานง่ายน้อยกว่าไฟล์ใด ๆ ที่มีรูปแบบไฟล์สามารถรองรับบรรทัดแรกที่เริ่มต้นด้วย#!
ตามด้วยเส้นทางแบบเต็มของไฟล์ที่เรียกทำงานได้จะมีบรรทัด Shebang หากคุณทำสิ่งนี้และไฟล์ถูกทำเครื่องหมายว่าปฏิบัติการคุณสามารถใช้งานได้เหมือนโปรแกรม ... ทำให้เปิดไฟล์ได้เหมือนเอกสาร
แอปพลิเคชั่นบางตัวใช้พฤติกรรมนี้โดยเจตนา ตัวอย่างเช่นใน VMware .vmx
ไฟล์จะกำหนดเครื่องเสมือน คุณสามารถ "เรียกใช้" เครื่องเสมือนเสมือนว่าเป็นสคริปต์เพราะไฟล์เหล่านี้มีการทำเครื่องหมายปฏิบัติการและมีบรรทัด shebang ทำให้สามารถเปิดได้ในยูทิลิตี้ VMware
rm
ลบไฟล์ มันไม่ใช่ภาษาสคริปต์ อย่างไรก็ตามไฟล์ที่เริ่มต้น#!/bin/rm
และถูกทำเครื่องหมายว่าสามารถเรียกใช้งานได้และเมื่อคุณเรียกใช้ไฟล์นั้นrm
จะถูกเรียกใช้โดยลบทิ้ง
สิ่งนี้มักจะเกิดขึ้นเมื่อ "ไฟล์ลบตัวเอง" แต่ไฟล์ไม่ได้ทำงานเลย นี่เป็นเหมือนสถานการณ์ที่อธิบายไว้ข้างต้นสำหรับ.vmx
ไฟล์
แต่ถึงกระนั้นเนื่องจาก#!
บรรทัดอำนวยความสะดวกในการทำงานของคำสั่งง่าย ๆ (รวมถึงอาร์กิวเมนต์บรรทัดคำสั่ง) คุณสามารถดำเนินการสคริปต์บางอย่างด้วยวิธีนี้ เป็นตัวอย่างง่ายๆของ "สคริปต์" ที่ซับซ้อนกว่า#!/bin/rm
ให้พิจารณา:
#!/usr/bin/env tee -a
สิ่งนี้จะนำผู้ใช้ป้อนข้อมูลแบบโต้ตอบสะท้อนกลับไปที่ผู้ใช้ทีละบรรทัดและต่อท้ายไฟล์ "สคริปต์"
มีประโยชน์หรือไม่ ไม่มาก. แนวคิดที่น่าสนใจ? โดยสิ้นเชิง! ใช่. (ค่อนข้าง.)
สคริป / โปรแกรมที่มีหลายภาษาในครั้งเดียวตัวอย่างเช่นในการจำลองการทำงาน hashbang ในระบบปฏิบัติการที่ไม่ได้มีมัน
(โปรแกรมเหล่านี้เรียกว่ารูปหลายเหลี่ยมแต่ไม่ควรสับสนกับความหมายอื่น ๆ ของรูปหลายภาษาในการพัฒนาซอฟต์แวร์โปรแกรม / โครงการที่ชิ้นส่วนต่าง ๆ เขียนเป็นภาษาต่าง ๆ )
Metacommandsในตัวเลือก QBasic / QuickBASIC ซึ่งส่งสัญญาณไปยังตัวเลือกคอมไพเลอร์ (สำหรับโค้ดที่คอมไพล์) สำหรับการสร้างโค้ด แต่เป็นส่วนหนึ่งของความคิดเห็นและละเว้นในระหว่างการรวบรวม / ตีความจริง
-x
ธงPythons ทำอะไร?
-x
"ข้าม [s] บรรทัดแรก ... " บรรทัดที่ 2 รับหมายเลข1
แทน2
บรรทัดที่ 3 2
แทน3
เป็นต้นนี่คือเหตุผลที่คุณไม่ควรใช้แฟล็กนั้น ;) -x
มีไว้สำหรับการเขียนสคริปต์บนระบบปฏิบัติการที่ไม่ใช่ยูนิกซ์ที่มีรูปแบบ Shebang เหมือนกับที่ไม่ได้ขึ้นต้นด้วย#
(ไม่ใช่ความคิดเห็นของ Python)
perl script.pl
กับ./script.pl
) แล้วล่ามจะอ่านบรรทัด shebang -w
เพื่อแยกธงเช่น ไม่แนะนำให้ใช้คุณลักษณะนี้
Shebang เป็นลำดับอักขระที่ประกอบด้วยเครื่องหมายหมายเลขอักขระและเครื่องหมายอัศเจรีย์ (เช่น "#!") เมื่อมันเกิดขึ้นเป็นอักขระสองตัวเริ่มต้นในบรรทัดเริ่มต้นของสคริปต์
ภายใต้ระบบปฏิบัติการ * ระวังเมื่อสคริปต์ที่เริ่มต้นด้วย shebang ถูกเรียกใช้งานตัวโหลดโปรแกรมจะแยกวิเคราะห์บรรทัดเริ่มต้นที่เหลือของสคริปต์เป็นคำสั่งล่าม โปรแกรมล่ามที่ระบุจะถูกเรียกใช้แทนโดยส่งผ่านเป็นอาร์กิวเมนต์สำหรับพา ธ ที่ถูกใช้ครั้งแรกเมื่อพยายามเรียกใช้สคริปต์ ตัวอย่างเช่นหากสคริปต์ตั้งชื่อด้วยพา ธ "path / to / your-script" และเริ่มต้นด้วยบรรทัดต่อไปนี้:
#!/bin/sh
จากนั้นตัวโหลดโปรแกรมจะได้รับคำสั่งให้รันโปรแกรม "/ bin / sh" แทนเช่น Bourne shell หรือเชลล์ที่เข้ากันได้โดยผ่าน "path / to / your-script" เป็นอาร์กิวเมนต์แรก
ดังนั้นสคริปต์จะถูกตั้งชื่อด้วยพา ธ "path / to / python-script" และเริ่มต้นด้วยบรรทัดต่อไปนี้:
#!/bin/python
จากนั้นโปรแกรมที่โหลดจะได้รับคำสั่งให้รันโปรแกรม "/ bin / python" แทนเช่น Python interpreter ผ่าน "path / to / python-script" เป็นอาร์กิวเมนต์แรก
ในระยะสั้น "#" จะแสดงความคิดเห็นออกบรรทัดในขณะที่ลำดับตัวละคร "#!" ที่เกิดขึ้นเป็นอักขระสองตัวแรกในบรรทัดเริ่มต้นของสคริปต์มีความหมายที่ระบุไว้ข้างต้น
สำหรับรายละเอียดดูทำไมสคริปต์บางตัวเริ่มต้นด้วย #! ...
ที่มา:บางส่วนของคำตอบนี้ได้มา (โดยมีการดัดแปลงเล็กน้อย) จากShebang (Unix)ในภาษาอังกฤษ Wikipedia (โดยผู้มีส่วนร่วม Wikipedia ) บทความนี้ได้รับอนุญาตภายใต้ CC-BY-SA 3.0เช่นเดียวกับเนื้อหาของผู้ใช้ที่นี่ใน AU ดังนั้นจึงอนุญาตให้มีการสืบทอดมาพร้อมกับการระบุแหล่งที่มา
#!
เรียกว่าshebang
เมื่อมันเกิดขึ้นเป็นตัวละครสองตัวเริ่มต้นในบรรทัดเริ่มต้นของสคริปต์ มันถูกใช้ในสคริปต์เพื่อระบุล่ามสำหรับการดำเนินการ The shebang
สำหรับระบบปฏิบัติการ (เคอร์เนล) ไม่ใช่สำหรับเชลล์ ดังนั้นมันจะไม่ถูกตีความว่าเป็นความคิดเห็น
มารยาท: http://en.wikipedia.org/wiki/Shebang_%28Unix%29
โดยทั่วไปถ้าไฟล์นั้นสามารถใช้งานได้ แต่จริงๆแล้วไม่ใช่โปรแกรมที่เรียกใช้งานได้ (ไบนารี่) และมีบรรทัดดังกล่าวอยู่โปรแกรมที่ระบุหลัง #! เริ่มต้นด้วยชื่อสคริปต์และอาร์กิวเมนต์ทั้งหมด อักขระสองตัวนี้ # และ! ต้องเป็นสองไบต์แรกในไฟล์!
ข้อมูลโดยละเอียด: http://wiki.bash-hackers.org/scripting/basics#the_shebang
ไม่มันถูกใช้โดยการexec
เรียกระบบของเคอร์เนล Linux เท่านั้นและถือว่าเป็นความคิดเห็นโดยล่าม
เมื่อคุณทุบตี:
./something
บน Linux นี้เรียกสายระบบกับเส้นทางexec
./something
บรรทัดของเคอร์เนลนี้ถูกเรียกบนไฟล์ที่ส่งไปยังexec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
#!
มันอ่านไบต์แรกของไฟล์และเปรียบเทียบพวกเขาไป
หากการเปรียบเทียบเป็นจริงดังนั้นส่วนที่เหลือของบรรทัดจะถูกวิเคราะห์โดยเคอร์เนล Linux ซึ่งทำให้การexec
เรียกด้วยพา ธ/usr/bin/env python
และไฟล์ปัจจุบันเป็นอาร์กิวเมนต์แรก:
/usr/bin/env python /path/to/script.py
และใช้ได้กับภาษาสคริปต์ใด ๆ ที่ใช้#
เป็นอักขระความคิดเห็น
และใช่คุณสามารถสร้างวงวนไม่สิ้นสุดด้วย:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash รู้จักข้อผิดพลาด:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
เพิ่งเกิดขึ้นกับมนุษย์อ่านได้ แต่ไม่จำเป็น
หากไฟล์เริ่มต้นด้วยไบต์ที่แตกต่างกันการexec
เรียกของระบบจะใช้ตัวจัดการที่แตกต่างกัน ตัวจัดการในตัวที่สำคัญที่สุดสำหรับไฟล์เรียกทำงานของ ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305ซึ่งจะตรวจสอบไบต์7f 45 4c 46
(ซึ่งเกิดขึ้นกับมนุษย์ด้วย) สามารถอ่านได้สำหรับ.ELF
) เรามายืนยันว่าโดยการอ่าน 4 ไบต์แรกของ/bin/ls
ซึ่งเป็นปฏิบัติการ ELF:
head -c 4 "$(which ls)" | hd
เอาท์พุท:
00000000 7f 45 4c 46 |.ELF|
00000004
ดังนั้นเมื่อเคอร์เนลเห็นไบต์เหล่านั้นจะใช้ไฟล์ ELF วางลงในหน่วยความจำอย่างถูกต้องและเริ่มกระบวนการใหม่ด้วย ดูเพิ่มเติมที่: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
ในที่สุดคุณสามารถเพิ่มตัวจัดการ Shebang ของคุณเองด้วยbinfmt_misc
กลไก ตัวอย่างเช่นคุณสามารถเพิ่มตัวจัดการที่กำหนดเองสำหรับ.jar
ไฟล์ กลไกนี้ยังรองรับตัวจัดการโดยนามสกุลไฟล์ การประยุกต์ใช้ก็คือการโปร่งใสทำงาน executables ของสถาปัตยกรรมที่แตกต่างกันกับ QEMU
ฉันไม่คิดว่า POSIX จะระบุ shebangs อย่างไรก็ตาม: https://unix.stackexchange.com/a/346214/32558ถึงแม้ว่ามันจะกล่าวถึงในส่วนของเหตุผลและในรูปแบบ "ถ้าสคริปต์ที่ปฏิบัติการได้รับการสนับสนุนจากระบบ เกิดขึ้น"
#include
คุณจะเห็น นั่นก็#
หมายความว่าไม่ได้เป็นความคิดเห็น