Vì tệp không thuộc bất kỳ loại thực thi nào được hệ thống nhận ra và giả sử bạn đã có quyền thực thi tệp đó, nên execve()cuộc gọi hệ thống thường sẽ thất bại với lỗi ENOEXEC( không phải là thực thi ).
Điều gì xảy ra sau đó tùy thuộc vào ứng dụng và / hoặc chức năng thư viện được sử dụng để thực thi lệnh.
Ví dụ, đó có thể là shell, hàm execlp()/ execvp()libc.
Hầu hết các ứng dụng khác sẽ sử dụng một trong những ứng dụng đó khi chúng chạy lệnh. Ví dụ, họ sẽ gọi shell bằng system("command line")hàm libc, thường sẽ gọi shđể phân tích dòng lệnh đó (đường dẫn có thể được xác định tại thời điểm biên dịch (như /bin/shso với /usr/xpg4/bin/shtrên Solaris)) hoặc gọi shell được lưu trữ $SHELLbởi chính họ như vivới !lệnh của nó hoặc xterm -e 'command line'nhiều lệnh khác ( su user -csẽ gọi shell đăng nhập của người dùng thay vì $SHELL).
Nói chung, một tệp văn bản không có shebang không bắt đầu #được coi là một shtập lệnh. Mà shnó sẽ thay đổi mặc dù.
execlp()/ execvp(), khi execve()trở về ENOEXECthường sẽ gọi shnó. Đối với các hệ thống có nhiều hơn một shvì chúng có thể tuân thủ nhiều hơn một tiêu chuẩn, shđiều này thường được xác định tại thời điểm biên dịch (của ứng dụng sử dụng execvp()/ execlp()bằng cách liên kết một blob mã khác nhau có liên quan đến một đường dẫn khác sh). Chẳng hạn, trên Solaris, đó sẽ là /usr/xpg4/bin/sh(một tiêu chuẩn, POSIX sh) hoặc /bin/sh(vỏ Bourne (vỏ cổ) trên Solaris 10 trở lên, ksh93 trong Solaris 11).
Khi nói đến đạn pháo, có rất nhiều biến thể. bash, AT & T ksh, shell Bourne thường sẽ tự giải thích tập lệnh (trong một quy trình con trừ khi execđược sử dụng) sau khi đã mô phỏng a execve(), đó là đặt tất cả các biến không được báo cáo, đóng tất cả các fds đóng-thực thi, loại bỏ tất cả các bẫy tùy chỉnh, bí danh, hàm ... ( bashsẽ diễn giải tập lệnh trong shchế độ). yashsẽ tự thực thi (với chế độ shnhư argv[0]vậy sh) để diễn giải nó.
zsh, pdksh, ashVỏ dựa trên thường sẽ gọi sh(con đường mà xác định tại thời gian biên dịch).
Đối với cshvà tcsh(và shcủa một số BSD đầu tiên), nếu ký tự đầu tiên của tệp là #, thì họ sẽ tự thực thi để giải thích nó, và shnếu không. Điều đó quay trở lại thời tiền shebang, nơi cshđã nhận ra #là bình luận nhưng không phải là vỏ Bourne, vì vậy đó #là một gợi ý rằng đó là một kịch bản csh.
fish(ít nhất là phiên bản 2.4.0), chỉ trả về lỗi nếu execve()không thành công (không cố xử lý nó như một tập lệnh).
Một số shell (như bashhoặc AT & T ksh) trước tiên sẽ cố gắng xác định một cách chính xác xem liệu tệp có thể có nghĩa là một tập lệnh hay không. Vì vậy, bạn có thể thấy rằng một số shell sẽ từ chối thực thi tập lệnh nếu nó có ký tự NUL trong vài byte đầu tiên.
Cũng lưu ý rằng nếu execve()thất bại với ENOEXEC nhưng tệp có dòng shebang, một số shell cố gắng tự giải thích dòng shebang đó.
Vì vậy, một vài ví dụ:
- Khi
$SHELLlà /bin/bash, xterm -e 'myscript with args'sẽ có myscriptgiải thích bởi bashtrong shchế độ. Trong khi với xterm -e myscript with args, xtermsẽ sử dụng execvp()để kịch bản sẽ được giải thích bởi sh.
su -c myscripttrên Solaris 10, nơi rootđăng nhập của shell /bin/shvà /bin/shlà shell Bourne sẽ được myscriptgiải thích bởi shell Bourne.
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'trên Solaris 10 sẽ có nó được giải thích bởi /usr/xpg4/bin/sh(tương tự cho /usr/xpg4/bin/env myscript).
find . -prune -exec myscript {} \;trên Solaris 10 (sử dụng execvp()) sẽ được giải thích /bin/shngay cả với /usr/xpg4/bin/find, ngay cả trong môi trường POSIX (lỗi tuân thủ).
csh -c myscriptsẽ được giải thích bởi cshnếu nó bắt đầu bằng #, shnếu không.
Nói chung, bạn không thể chắc chắn cái vỏ nào sẽ được sử dụng để diễn giải kịch bản đó nếu bạn không biết nó sẽ được gọi như thế nào và bằng cách nào.
Trong mọi trường hợp, read -plà bashcú pháp đơn thuần, vì vậy bạn sẽ muốn đảm bảo rằng tập lệnh được diễn giải bởi bash(và tránh .shphần mở rộng gây hiểu lầm đó ). Hoặc bạn biết đường dẫn của bashtệp thực thi và sử dụng:
#! /path/to/bash -
read -p ...
Hoặc bạn có thể thử và dựa vào $PATHtra cứu bashthực thi (giả sử đã bashđược cài đặt) bằng cách sử dụng:
#! /usr/bin/env bash
read -p ...
( envhầu như có mặt khắp nơi trong /usr/bin). Ngoài ra, bạn có thể làm cho nó tương thích POSIX + Bourne trong trường hợp bạn có thể sử dụng /bin/sh. Tất cả các hệ thống sẽ có một /bin/sh. Trên hầu hết chúng sẽ tương thích (đối với hầu hết các phần) tương thích POSIX, nhưng bạn vẫn có thể tìm thấy bây giờ và sau đó là một vỏ Bourne ở đó.
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"