เนื่องจากไฟล์นั้นไม่ได้เป็นประเภทของการปฏิบัติการที่ระบบรู้จักและสมมติว่าคุณได้รับอนุญาตให้เรียกใช้ไฟล์นั้นการexecve()
เรียกใช้ระบบโดยทั่วไปจะล้มเหลวพร้อมกับข้อผิดพลาดENOEXEC
( ไม่ใช่การปฏิบัติการ )
สิ่งที่เกิดขึ้นนั้นขึ้นอยู่กับแอปพลิเคชันและ / หรือฟังก์ชั่นห้องสมุดที่ใช้ในการดำเนินการคำสั่ง
ที่สามารถเป็นเช่นเปลือกฟังก์ชันexeclp()
/ execvp()
libc
แอปพลิเคชันอื่น ๆ ส่วนใหญ่จะใช้อย่างใดอย่างหนึ่งของพวกเขาเมื่อพวกเขาเรียกใช้คำสั่ง พวกเขาจะเรียกเปลือกเช่นโดยวิธีการของsystem("command line")
ฟังก์ชัน libc ซึ่งโดยทั่วไปจะเรียกsh
ให้แยกวิเคราะห์บรรทัดคำสั่งนั้น (เส้นทางที่สามารถกำหนดได้ในเวลาคอมไพล์ (เช่น/bin/sh
vs /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
ค้นหาของbash
executable (สมมติว่า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"