การเขียนเชลล์สคริปต์ที่จะทำงานบนเชลล์ใด ๆ (ใช้หลายบรรทัด Shebang?)


19

ฉันเพิ่งเริ่มเข้าใจเชลล์สคริปต์มากขึ้นและฉันก็แค่โยนสคริปต์ลงในไฟล์ทำเครื่องหมายchmod +xและทำทุกอย่างแล้ว/path/to/script.shให้ล่ามทุกตัวที่เป็นค่าเริ่มต้นมีทางด้วยซึ่งฉันคิดว่าเป็น zsh เพราะนั่นคือสิ่งที่ ฉันใช้เปลือกของฉัน เห็นได้ชัดว่ามันก็ดูเหมือนว่ามันเป็นเพียง/bin/shโดยค่าเริ่มต้นแม้ว่าผมจะรันสคริปต์จาก zsh พรอมต์เพราะผมเริ่มวางสิ่ง zsh zsh /path/to/script.shเฉพาะในสคริปต์ของฉันและมันก็ล้มเหลวถ้าฉันทำงาน

เพื่อให้ตรงประเด็นนี่คือคำถามของฉัน:

  1. เชลล์ตัวไหนรันสคริปต์เมื่อไม่มีบรรทัด shebang ( #!/path/to/shell) ที่จุดเริ่มต้น? ฉันถือว่า/bin/shแต่ฉันไม่สามารถยืนยันได้
  2. อะไรคือ "แนวทางปฏิบัติที่ดีที่สุด" ในแง่ของการเขียนเชลล์สคริปต์ที่จะทำงานบนแพลตฟอร์มใด ๆ (ตกลงนี่เป็นแบบปลายเปิด)
  3. เป็นไปได้ไหมที่จะเขียนสคริปต์ที่พยายามใช้ zsh และกลับไปใช้ทุบตีหาก zsh ไม่พร้อมใช้งาน? ฉันได้ลองใส่ Shebang สองบรรทัดเช่นด้านล่าง แต่มันก็ผิดพลาดbad interpreter: /bin/zsh: no such file or directoryถ้าฉันลองมันบนเครื่องที่ไม่มี zsh

    #!/bin/zsh

    #!/bin/bash

คำตอบ:


26

เชลล์ตัวไหนรันสคริปต์เมื่อไม่มีบรรทัด shebang (#! / path / to / shell) ที่จุดเริ่มต้น? ฉันถือว่า / bin / sh แต่ฉันไม่สามารถยืนยันได้

เคอร์เนลปฏิเสธที่จะรันสคริปต์ดังกล่าวและผลตอบแทน ENOEXEC ดังนั้นพฤติกรรมที่แน่นอนขึ้นอยู่กับโปรแกรมที่คุณเรียกใช้สคริปต์ดังกล่าวจาก

  • bash 4.2.39 - ใช้ตัวมันเอง
  • busybox-ash 1.20.2 - ใช้ตัวมันเอง
  • เส้นประ 0.5.7 - วิ่ง / bin / sh
  • ปลา 1.23.1 - บ่นเกี่ยวกับ ENOEXEC แล้วโทษไฟล์ผิด
  • AT&T ksh 93u + 2012.08.01 - ใช้ตัวมันเอง
  • mksh R40f - ทำงาน / bin / sh
  • pdksh 5.2.14 - ทำงาน / bin / sh
  • sh-heirloom 050706 - ใช้ตัวมันเอง
  • tcsh 6.18.01 - ทำงาน / bin / sh
  • zsh 5.0.0 - วิ่ง / bin / sh
  • cmd.exe 5.1.2600 - ดูแล้วคุณตลก

ในglibc , ฟังก์ชั่นexecv()หรือexecve()เพียงแค่คืนค่า ENOEXEC แต่execvp()ซ่อนรหัสข้อผิดพลาดนี้และจะเรียกใช้ / bin / sh โดยอัตโนมัติ (นี่คือเอกสารในexec (3p) )

อะไรคือ "แนวทางปฏิบัติที่ดีที่สุด" ในแง่ของการเขียนเชลล์สคริปต์ที่จะทำงานบนแพลตฟอร์มใด ๆ (ตกลงนี่เป็นแบบปลายเปิด)

ทั้งติดshและคุณสมบัติเฉพาะ POSIX ที่กำหนดไว้หรือเพียงแค่ไปเต็มทุบตี (ซึ่งสามารถใช้ได้อย่างกว้างขวาง) และพูดถึงมันในความต้องการของคุณถ้ากระจาย

(ตอนนี้ฉันคิดว่ามัน Perl - หรือบางทีหลาม - จะพกพามากขึ้นไม่ต้องพูดถึงว่ามีไวยากรณ์ที่ดีกว่า)

เสมอเพิ่มบรรทัด shebang หากใช้ bash หรือ zsh ให้ใช้#!/usr/bin/env bashแทน hardcoding พา ธ ของเชลล์ (อย่างไรก็ตาม POSIX เชลล์รับประกันว่าจะเป็น/bin/shดังนั้นให้ข้ามenvในกรณีนั้น)

(น่าเสียดายที่แม้/bin/shจะไม่เหมือนกันเสมอโปรแกรมautoconf ของ GNU ต้องจัดการกับนิสัยใจคอต่างๆ )

เป็นไปได้ไหมที่จะเขียนสคริปต์ที่พยายามใช้ zsh และกลับไปใช้ทุบตีหาก zsh ไม่พร้อมใช้งาน? ฉันได้ลองใส่ Shebang สองบรรทัดอย่างเช่นด้านล่าง แต่มันเป็นแค่ข้อผิดพลาดกับล่ามที่ไม่ดี: / bin / zsh: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าวถ้าฉันลองใช้กับเครื่องที่ไม่มี zsh

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

เป็นไปได้ที่จะเขียนสคริปต์ที่ทำงานเป็น#!/bin/shตรวจสอบว่าเชลล์ใดที่พร้อมใช้งานและรันexec zsh "$0" "$@"หรือexec bash "$0" "$@"ขึ้นอยู่กับผลลัพธ์ อย่างไรก็ตามไวยากรณ์ที่ใช้โดย bash และ zsh นั้นแตกต่างกันมากในหลาย ๆ ที่ที่ฉันไม่แนะนำให้ทำเพื่อความมีสติของคุณ


1
คุณติดตามสิ่งที่แต่ละเชลล์เรียกจริง ๆ เมื่อได้รับ ENOEXEC ได้อย่างไร
swrobel

2
@SWrobel: strace -f -e fork,clone,execveการใช้ เชลล์บางตัวยังดำเนินต่อไป/bin/shหลังจากเกิดความล้มเหลว คนอื่นตีความตัวเองสคริปต์
grawity

1
@SWrobel: readlink /proc/$$/exeอีกวิธีหนึ่งคือการใช้สคริปต์ที่ประกอบด้วย
grawity


1
สำหรับcshและtcshพฤติกรรมขึ้นอยู่กับว่าสคริปต์เริ่มต้นด้วย#(ในกรณีที่พวกเขาเรียกตัวเองแทนที่จะดวลจุดโทษเพื่อตีความสคริปต์) ย้อนกลับไปในช่วงเวลาที่ csh สนับสนุนความคิดเห็น แต่ไม่ใช่เชลล์เป้าหมายดังนั้น a #จึงมีคำใบ้ว่าเป็นสคริปต์ csh
sch

2

1) เชลล์ปัจจุบันที่คุณใช้งานอยู่ (เชลล์ใดก็ตามที่อาจเป็น)

2) ติดกับเชลล์ประเภทเดียวกัน (bash / dash / ash / csh / อะไรก็ตามที่คุณชอบ) และให้แน่ใจว่า "แพลตฟอร์มที่รองรับ" ของคุณติดตั้งเชลล์ที่คุณต้องการใช้เป็นค่าเริ่มต้น นอกจากนี้ลองใช้คำสั่งที่มีอยู่ทั่วไปในระบบ หลีกเลี่ยงตัวเลือกเฉพาะเครื่อง

3) มีไม่ได้จริงๆ "ถ้า-แล้วอื่น" interpreter directiveตรรกะไป คุณควรระบุเชลล์ที่ควรมีอยู่ในทุกระบบที่คุณต้องการสนับสนุน ... เช่น#!/bin/bashหรือระบุทั่วไป#!/bin/shตราบใดที่สคริปต์ของคุณมีความเป็นธรรมทั่วทั้งเชลล์

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