ใน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คุณจะเห็น นั่นก็#หมายความว่าไม่ได้เป็นความคิดเห็น