Chạy một kịch bản shell khi sử dụng các ứng dụng shell / bin / sh


11

Tôi đã đọc những điều sau đây trong câu hỏi này :

bash hỗ trợ một công tắc --poseix, làm cho nó phù hợp hơn với POSIX. Nó cũng cố gắng bắt chước POSIX nếu được gọi là sh .

Các trích dẫn ở trên giả định rằng đó /bin/shlà một liên kết trỏ đến /bin/bash.

Nhưng tôi hoàn toàn không hiểu ý nghĩa của "được gọi là sh" .


Nói rằng tôi có đoạn script sau được gọi là "script.sh":

#!/bin/bash
echo "Hello World"

Vui lòng cho tôi biết trong mỗi trường hợp sau đây liệu tập lệnh sẽ được chạy ở bashchế độ bình thường hay ở chế độ POSIX (giả sử rằng tôi đã thực hiện các lệnh sau trong một thiết bị đầu cuối đang chạy bash):

  1. sh script.sh
  2. bash script.sh
  3. ./script.sh

Bây giờ hãy nói rằng tôi có đoạn script sau được gọi là "script.sh" (giống như đoạn script trên nhưng không có shebang):

echo "Hello World"

Vui lòng cho tôi biết trong mỗi trường hợp sau đây liệu tập lệnh sẽ được chạy ở bashchế độ bình thường hay ở chế độ POSIX (giả sử rằng tôi đã thực hiện các lệnh sau trong một thiết bị đầu cuối đang chạy bash):

  1. sh script2.sh
  2. bash script2.sh
  3. ./script2.sh

Câu trả lời:


19

Chỉ các trường hợp 1 & 4 sẽ chạy trong chế độ POSIX (giả sử đó shlà bash và không phải là một số triển khai khác của sh). Bất kỳ trường hợp nào gọi rõ ràng bashmà không có, --posixsẽ không từ shebang hay không. Bất kỳ trường hợp nào gọi rõ ràng shsẽ. Shebang chỉ được sử dụng khi không có shell nào được khởi động rõ ràng cho tập lệnh rồi.

Trường hợp 6, nếu thiết bị đầu cuối của bạn đang chạy bash, sẽ không chạy trong chế độ POSIX và Bash sẽ gọi nó bằng chính nó. Nếu thiết bị đầu cuối của bạn đang chạy zsh thay vào đó, trường hợp 6 cũng sẽ chạy ở chế độ POSIX. POSIX mơ hồ về chính xác những gì sẽ xảy ra trong trường hợp đó , và Bash và zsh đã đưa ra những lựa chọn khác nhau ở đó. Bash gọi kịch bản bằng chính nó, trong khi zsh sử dụng sh(bất cứ điều gì xảy ra). Các vỏ khác cũng khác nhau về điểm đó.


Một cách đơn giản để cho biết bạn đang ở chế độ nào là tạo thân tập lệnh:

kill -SIGHUP

sẽ không thành công với lỗi trong chế độ POSIX , nhưng đưa ra hướng dẫn sử dụng cho killbên ngoài nó. Đây là một sự phân biệt dễ dàng và nó hoạt động thông qua một loạt các phiên bản Bash sẽ quay trở lại xa như bạn có thể gặp phải.


3
Có những thứ khác sẽ buộc bashphải chạy trong chế độ POSIX như POSIXLY_CORRECTbiến môi trường hoặc SHELLOPTS=posix.
Stéphane Chazelas

1
[ -o posix ]là một cách rõ ràng hơn để kiểm tra xem bạn đang chạy ở chế độ posix trong bash (không phải trong các shell khác (trừ yash), vì vậy bạn sẽ không muốn làm điều đó trong một shtập lệnh). POSIXLY_CORRECT=1 bash -c '[ -o posix ] && echo yes'đầu ra yes`
Stéphane Chazelas

2
Trong trường hợp 6, bash gọi tập lệnh ở chế độ POSIX khi chính nó ở chế độ POSIX như POSIX yêu cầu. POSIX không chỉ định cơ chế cô ấy và 6 là cách POSIX duy nhất có các tập lệnh thực thi và được chỉ định rõ ràng (trong môi trường POSIX, tập lệnh có nghĩa là được hiểu bởi tiện ích sh tuân thủ).
Stéphane Chazelas

8

"Được gọi là" đề cập đến bất cứ điều gì mà quá trình bắt đầu Bash đưa vào đối số dòng lệnh "zeroth" của nó , argv[0].

Khi một chương trình được bắt đầu với exec*()syscalls , họ không thực sự làm quen với tên của tập tin nhị phân chứa các chương trình, nhưng thay vào đó là quá trình gọi là miễn phí để đặt bất cứ điều gì nó muốn ở đó. Tất nhiên, thông thường, tên được lấy từ hệ thống tập tin, vì vậy nếu bạn chạy /bin/sh, đó là những gì được đặt ở đó. Và nếu /bin/shlà Bash, nó không phải là một liên kết tượng trưng, ​​nó có thể là một liên kết cứng hoặc chỉ là một bản sao khác của chương trình shell.

Như một ví dụ về việc đặt "tên chương trình", execlệnh của Bash có thể đặt đối số zeroth với -atùy chọn. (Chúng ta có thể làm tương tự với Perl hoặc trực tiếp với C, v.v.)

Đây mynamelà một chương trình C đơn giản chỉ in đối số zeroth của nó, tên mà nó tự thấy:

$ ./myname 
I am ./myname
$ (exec -a something ./myname )
I am something
$ mv ./myname somename
$ ln -s somename othername
$ ./somename 
I am ./somename
$ ./othername
I am ./othername

Nguồn:

#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("I am %s\n", argv[0]);
    return 0;
}

Nhưng, để trả lời các câu hỏi được đánh số ...

(1 & 4) chạy sh somescriptsẽ chạy bất cứ thứ gì shcó trên bạn PATH, có thể /bin/shnhưng có thể là thứ gì đó như thế/usr/xpg4/bin/sh .

  • Nếu là Bash, nó chạy ở chế độ POSIX, vì nó nhìn thấy tên sh.
  • Nếu là vỏ Z hoặc vỏ Korn, thì nó cũng nhìn thấy tên đó sh, nhưng nó chạy ở chế độ "tương thích SH", nhằm mục đích tương thích với vỏ Bourne và khác biệt với chế độ tuân thủ POSIX đầy đủ trong cả hai vỏ đó .
  • Nó có thể là vỏ Almquist, vỏ Bourne thực tế, hoặc một cái gì đó khác, tất nhiên.

(2 & 5) Chạy bash somescriptsẽ chạy trong chế độ Bash thông thường (một lần nữa, tất nhiên nó phụ thuộc vào những gì bashtrong bạn PATH.)

(3) Ở đây, tên của tập lệnh được đặt trực tiếp cho lệnh gọi hệ thống thay cho tệp chương trình. Nhân đọc dòng hashbang và sử dụng nó để chạy tập lệnh.

(6) Đây là một trong những phức tạp. Nó tương tự như (3), nhưng lệnh hệ thống để bắt đầu chương trình không thành công ( ENOEXEC (Exec format error)), vì không có dòng hashbang. Chuyện gì xảy ra tiếp theo phụ thuộc từ liệu vỏ mà bạn đang chạy là bản thân trong chế độ POSIX. POSIX yêu cầu lớp vỏ phù hợp POSIX hoạt động theo kiểu cụ thể để đáp ứng ENOEXEC. Tuy nhiên, có một số độ trễ trong "một lệnh tương đương với việc gọi shell" có nghĩa là các shell khác nhau làm những việc khác nhau.

  • Shell Bourne Again tự chạy lại trong cùng chế độ với tên của tập lệnh là đối số dòng lệnh đầu tiên của nó. Trong chế độ tuân thủ POSIX, dĩ nhiên nó tự chạy ở chế độ tuân thủ POSIX, do đó tuân theo yêu cầu POSIX để gọi vỏ phù hợp POSIX.
  • Shell Z, Almquist shell và Korn shell chạy /bin/shvới tên của tập lệnh được chèn trước các đối số khác làm đối số dòng lệnh đầu tiên của nó. Vỏ Z, vỏ Almquist và vỏ Korn (đang cố gắng) gọi vỏ phù hợp POSIX bằng cách giả định rằng /bin/shchương trình là một.

Bạn có thể vui lòng chia sẻ mã nguồn của chương trình C này không ..
GypsyCosmonaut

int main(int argc, char *argv[]){printf("I am %s\n",argv[0]);}
Stig Hemmer

Nó khá là nhiều.
ilkkachu

4

Vỏ thực hiện là một trong hai người gọi trong dòng lệnh hoặc một trong các công việc (nếu dòng lệnh không xác định nó).

Vì vậy, phiên bản 1 và 4 sẽ chạy cùng sh, 2 và 5 với bash và 6 có thể không chạy nếu bạn đang sử dụng sh (và một số người khác) tương tác. Bash không bắt đầu kịch bản. Ksh cũng vậy. Zsh bắt đầu nó như sh.

Chỉ những người bắt đầu như shsẽ sử dụng tùy chọn posix nếu bash được liên kết đến /bin/sh.

Thêm dòng này vào tập lệnh của bạn để phát hiện xem có phiên bản bash ksh hoặc zsh nào đang chạy không:

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.