เนื่องจากไฟล์นั้นไม่ได้เป็นประเภทของการปฏิบัติการที่ระบบรู้จักและสมมติว่าคุณได้รับอนุญาตให้เรียกใช้ไฟล์นั้นการexecve()เรียกใช้ระบบโดยทั่วไปจะล้มเหลวพร้อมกับข้อผิดพลาดENOEXEC( ไม่ใช่การปฏิบัติการ )
สิ่งที่เกิดขึ้นนั้นขึ้นอยู่กับแอปพลิเคชันและ / หรือฟังก์ชั่นห้องสมุดที่ใช้ในการดำเนินการคำสั่ง
ที่สามารถเป็นเช่นเปลือกฟังก์ชันexeclp()/ execvp()libc
แอปพลิเคชันอื่น ๆ ส่วนใหญ่จะใช้อย่างใดอย่างหนึ่งของพวกเขาเมื่อพวกเขาเรียกใช้คำสั่ง พวกเขาจะเรียกเปลือกเช่นโดยวิธีการของsystem("command line")ฟังก์ชัน libc ซึ่งโดยทั่วไปจะเรียกshให้แยกวิเคราะห์บรรทัดคำสั่งนั้น (เส้นทางที่สามารถกำหนดได้ในเวลาคอมไพล์ (เช่น/bin/shvs /usr/xpg4/bin/shบน Solaris)) หรือเรียกใช้เชลล์ที่จัดเก็บ$SHELLด้วยตนเองเช่นviด้วย !คำสั่งหรือxterm -e 'command line'คำสั่งอื่น ๆ อีกมากมาย ( su user -cจะเรียกเชลล์ล็อกอินของผู้ใช้แทน$SHELL)
โดยทั่วไปแล้วไฟล์ข้อความแบบ shebang-less ที่ไม่ได้ขึ้นต้น#จะถือเป็นshสคริปต์ ซึ่งshมันจะแตกต่างกันไป
execlp()/ execvp()เมื่อexecve()กลับมาENOEXECโดยทั่วไปจะเรียกใช้shบน สำหรับระบบที่มีมากกว่าหนึ่งshเพราะพวกเขาสามารถสอดคล้องกับมาตรฐานมากกว่าหนึ่งมาตรฐานซึ่งshโดยทั่วไปจะถูกกำหนดในเวลารวบรวม (ของแอปพลิเคชันที่ใช้execvp()/ execlp()โดยการเชื่อมโยงหยดรหัสอื่นที่อ้างถึงเส้นทางที่แตกต่างกันไปsh) ตัวอย่างเช่นบน Solaris ซึ่งจะเป็น/usr/xpg4/bin/sh(มาตรฐาน, POSIX sh) หรือ/bin/sh(เชลล์เป้าหมาย (เชลล์โบราณ) บน Solaris 10 และเก่ากว่า, ksh93 ใน Solaris 11)
เมื่อพูดถึงกระสุนมันมีการเปลี่ยนแปลงมากมาย bash, AT&T kshโดยปกติแล้วเชลล์เป้าหมายจะตีความสคริปต์เอง (ในกระบวนการย่อยเว้นแต่execจะใช้) หลังจากทำการจำลองexecve() , ซึ่งเป็นการตั้งค่าตัวแปรที่ไม่ได้ส่งออกทั้งหมด, ปิด fds โคลสออป -s-exec ทั้งหมด, ลบกับดักที่กำหนดเองทั้งหมด, ชื่อแทนฟังก์ชั่น ... ( bashจะแปลสคริปต์ในshโหมด) yashจะดำเนินการตัวเอง (ด้วยshเช่นargv[0]ในshโหมด) เพื่อตีความมัน
zsh, pdksh, ashเปลือกหอยชั่นโดยทั่วไปจะเรียกsh(เส้นทางที่กำหนดในเวลาเรียบเรียง)
สำหรับcshและtcsh(และshบางส่วนของ BSD ก่อนหน้า) หากอักขระตัวแรกของไฟล์อยู่#พวกเขาจะดำเนินการเพื่อตีความมันและshอื่น ๆ ย้อนกลับไปในช่วงก่อนพรีแบงก์ที่cshจำได้#ว่าเป็นความคิดเห็น แต่ไม่ใช่เชลล์บอร์นดังนั้น#คำใบ้ก็คือมันเป็นสคริปต์ csh
fish(อย่างน้อยรุ่น 2.4.0) เพียงแค่ส่งคืนข้อผิดพลาดหากexecve()ล้มเหลว (จะไม่พยายามถือเป็นสคริปต์)
เชลล์บางตัว (เช่นbashหรือ AT&T ksh) จะพยายามตรวจสอบด้วยตนเองก่อนว่าไฟล์นั้นน่าจะเป็นสคริปต์หรือไม่ ดังนั้นคุณอาจพบว่าบางเชลล์จะปฏิเสธที่จะรันสคริปต์ถ้ามันมีตัวอักษร NUL ในสองสามไบต์แรก
นอกจากนี้โปรดทราบว่าหากexecve()ล้มเหลวด้วย ENOEXEC แต่ไฟล์มีเส้น Shebang เชลล์บางตัวจะพยายามตีความว่า Shebang เรียงตัวเอง
ตัวอย่างเล็ก ๆ น้อย ๆ :
- เมื่อ
$SHELLเป็น/bin/bash, xterm -e 'myscript with args'จะมีการmyscriptตีความโดยbashในshโหมด ในขณะที่xterm -e myscript with args, xtermจะใช้execvp()เพื่อให้สคริปต์จะถูกตีความโดยshเพื่อให้สคริปต์จะถูกตีความโดย
su -c myscriptบน Solaris 10 ที่ซึ่งrootเชลล์ล็อกอินคือ/bin/shและ/bin/shเชลล์บอร์นจะมีmyscriptตีความโดยบอร์นเชลล์
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'บน Solaris 10 จะมีการตีความโดย/usr/xpg4/bin/sh(เหมือนกันสำหรับ/usr/xpg4/bin/env myscript )
find . -prune -exec myscript {} \;บน Solaris 10 (การใช้execvp()) จะมีการตีความโดย/bin/shแม้กับ/usr/xpg4/bin/findแม้ในสภาพแวดล้อม POSIX (ข้อผิดพลาดความสอดคล้อง)
csh -c myscriptจะมีการตีความโดยcshถ้าเริ่มต้น#ด้วยshมิฉะนั้น
สรุปคุณไม่สามารถแน่ใจได้ว่าจะใช้เชลล์ใดในการตีความสคริปต์นั้นถ้าคุณไม่ทราบว่ามันจะถูกเรียกใช้อย่างไรและอย่างไร
ไม่ว่าในกรณีใด ๆread -pคือbash- ไวยากรณ์เท่านั้นดังนั้นคุณต้องแน่ใจว่าสคริปต์ถูกตีความโดยbash(และหลีกเลี่ยง.shส่วนขยายที่ทำให้เข้าใจผิด) ไม่ว่าคุณจะรู้เส้นทางของการbashปฏิบัติการและการใช้งาน:
#! /path/to/bash -
read -p ...
หรือคุณสามารถลองและพึ่งพาการ$PATHค้นหาของbashexecutable (สมมติว่าbashมีการติดตั้ง) โดยใช้:
#! /usr/bin/env bash
read -p ...
( envพบเกือบทุกหนทุกแห่งใน/usr/bin) หรือคุณสามารถทำให้ POSIX + Bourne สามารถใช้งานร่วมกันได้ในกรณีที่คุณสามารถ/bin/shใช้ได้ /bin/shระบบทั้งหมดจะมี ส่วนใหญ่มันจะเป็น (ส่วนใหญ่) เข้ากันได้กับ POSIX แต่คุณยังอาจพบตอนนี้และจากนั้นบอร์นเชลล์ที่นั่นแทน
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"