Có đúng không khi sử dụng / bin / sh trong hashbang nếu shell Bourne không có sẵn trong bản phân phối?


15

Nói chung, shell script chứa nhận xét sau ở dòng đầu tiên của tệp script : #!/bin/sh. Theo các nghiên cứu mà tôi đã thực hiện, đây được gọi là "băm bang" và đó là nhận xét thông thường. Nhận xét này thông báo cho Unix rằng tệp này được Bourne Shell thực thi trong thư mục /bin.

Câu hỏi của tôi bắt đầu ở điểm đó. Cho đến bây giờ tôi chưa thấy bình luận này như thế nào #!/bin/bash. Nó luôn luôn là #!/bin/sh. Tuy nhiên, các bản phân phối Ubuntu không có chương trình Bourne Shell. Họ có Bourne Again Shell (bash).

Trong thời điểm đó, có đúng không khi đặt bình luận #!/bin/shtrong các tập lệnh shell được viết trong bản phân phối Ubuntu?



1
Xem câu trả lời của tôi cho câu hỏi về lỗi máy chủ này: #! / Bin / sh vs #! / Bin / bash để có tính di động tối đa .
Gordon Davisson

Thường được gọi làshebang
fpmurphy

Câu trả lời:


16

#!/bin/shnên hoạt động trên tất cả các bản phân phối giống Unix và Unix. Nó thường được coi là hashbang di động nhất miễn là tập lệnh của bạn được tuân thủ POSIX. Lớp /bin/shvỏ được cho là lớp vỏ thực hiện tiêu chuẩn vỏ POSIX, bất kể lớp vỏ thực sự được giả trang là /bin/shlớp vỏ.


#!/bin/shthông thường chỉ là một liên kết bây giờ vì vỏ Bourne không còn được duy trì. Trên nhiều hệ thống Unix /bin/shsẽ là một liên kết đến /bin/kshhoặc /bin/ash, trên nhiều hệ thống Linux dựa trên RHEL, nó sẽ là một liên kết đến /bin/bash, tuy nhiên trên Ubuntu và nhiều hệ thống dựa trên Debian, nó là một liên kết đến /bin/dash. Tất cả các shell, khi được gọi là sh, sẽ vào chế độ tương thích POSIX.

Hashbang là một trình giữ chỗ quan trọng mặc dù vì nó cho phép tính di động cao hơn nhiều so với các phương thức khác, miễn là tập lệnh của bạn tuân thủ nghiêm ngặt POSIX (lặp đi lặp lại mức độ quan trọng).

Lưu ý: Khi bashđược gọi trong chế độ POSIX, nó vẫn sẽ cho phép một số thứ không phải POSIX như [[, mảng và hơn thế nữa. Những thứ đó có thể thất bại trên một bashhệ thống không .


3
"Trên Ubuntu, nó là một liên kết đến / bin / dash" và nói chung các hệ thống dựa trên Debian khác. IIRC trên FreeBSD / GhostBSD cũng là một liên kết tượng trưng /bin/ash.
Sergiy Kolodyazhnyy

Để có thể di động hoàn toàn, hãy đặt một khoảng trắng giữa shebang và đường dẫn trình thông dịch (tuyệt đối). Một số hệ thống tìm kiếm #! /thay vì chỉ #!.
Simon Richter

5
@SimonRichter Một tài liệu tham khảo cho điều này sẽ rất tốt để xem.
Kusalananda

@SergiyKolodyazhnyy Phiên bản cài đặt của sh trên FreeBSD là tro và không phải là một liên kết tượng trưng.
Cướp

2
@Kusalananda, hmm, trang này nói rằng đây là một huyền thoại, vì vậy nó có thể bị coi nhẹ.
Simon Richter

12

Bạn đã có nó lạc hậu. /bin/shgần như không bao giờ là vỏ Bourne ngày nay, và đó là khi bạn gặp vấn đề khi sử dụng #! /bin/shcô ấy.

Vỏ Bourne là một vỏ được viết vào cuối những năm 70 và thay thế cho vỏ Thompson trước đây (còn được gọi là sh). Đầu những năm 80, David Korn đã viết một vài phần mở rộng cho shell Bourne, sửa một vài lỗi và sự lúng túng trong thiết kế (và giới thiệu một số) và gọi nó là shell Korn.

Đầu những năm 90, POSIX đã chỉ định sh ngôn ngữ dựa trên một tập hợp con của vỏ Korn và hầu hết các hệ thống hiện đã thay đổi thành /bin/shvỏ Korn hoặc vỏ phù hợp với đặc điểm kỹ thuật đó. Trong trường hợp BSD, /bin/shban đầu họ đã thay đổi (ban đầu (sau khi họ không còn có thể sử dụng vỏ Bourne vì lý do giấy phép), vỏ Almquist, một bản sao của vỏ Bourne với một số phần mở rộng ksh để nó trở thành tuân thủ POSIX.

Ngày nay, tất cả các hệ thống POSIX đều có vỏ được gọi sh(thường xuyên nhất, nhưng không nhất thiết phải có /bin, POSIX không chỉ định đường dẫn của các tiện ích mà nó chỉ định) mà hầu hết là tuân thủ POSIX. Nó thường dựa trên ksh88, ksh93, pdksh, bash, ash hoặc zsh², nhưng không phải là vỏ Bourne vì vỏ Bourne không bao giờ tuân thủ POSIX. Một vài trong số những vỏ ( bash, zsh, yashvà một số pdkshdẫn xuất cho phép một chế độ POSIX-compliant khi gọi là shít phù hợp khác).

bash(câu trả lời GNU cho shell Korn) thực sự là shell nguồn mở duy nhất (và người ta chỉ có thể nói hiện tại được duy trì vì những cái khác thường dựa trên ksh88 không có bất kỳ tính năng mới nào kể từ những năm 90) đã được chứng nhận là là một tiêu chuẩn POSIX sh(như một phần của chứng nhận macOS).

Khi bạn viết một tập lệnh bằng một cú #! /bin/sh -đánh, bạn nên sử dụng một shcú pháp tiêu chuẩn (và cũng nên sử dụng cú pháp tiêu chuẩn cho các tiện ích được sử dụng trong tập lệnh đó nếu bạn muốn có thể di động, nó không chỉ là trình bao có liên quan khi diễn giải trình bao tập lệnh), sau đó không quan trọng việc triển khai shtrình thông dịch cú pháp chuẩn đó được sử dụng ( ksh, bash...).

Không có vấn đề gì khi những cái vỏ đó có phần mở rộng so với tiêu chuẩn miễn là bạn không sử dụng chúng. Nó giống như để viết mã C, miễn là bạn viết mã C tiêu chuẩn và không sử dụng các phần mở rộng của một trình biên dịch (như gcc) hoặc khác, mã của bạn sẽ biên dịch OK bất kể việc triển khai trình biên dịch với điều kiện trình biên dịch tuân thủ.

Ở đây, với bạn #! /bin/shcô-bang, vấn đề chính của bạn sẽ là hệ thống mà /bin/shlà Bourne shell rằng ví dụ không hỗ trợ tính năng tiêu chuẩn như $((1+1)), $(cmd), ${var#pattern}... Trong trường hợp này bạn có thể cần công việc ở quanh như:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

Nhân tiện, Ubuntu /bin/shkhông phải là bashmặc định. Đó là dashnhững ngày này, một lớp vỏ đó là dựa trên NetBSD sh, bản thân dựa trên vỏ Almquist mà chủ yếu là POSIX compliant ngoại trừ việc nó không hỗ trợ ký tự nhiều byte. Trên Ubuntu và các hệ thống dựa trên Debian khác, bạn có thể chọn giữa bashdashcho /bin/shvới dpkg-reconfigure dash) 4 . shcác tập lệnh được cung cấp với Debian sẽ hoạt động giống nhau trong cả hai hệ vỏ vì chúng được ghi theo tiêu chuẩn chính sách Debian (siêu bộ của tiêu chuẩn POSIX). Có thể bạn sẽ thấy họ cũng làm việc OK trong zsh's shthi đua hay bosh(có lẽ không ksh93hay yashmà không có một localBUILTIN (theo yêu cầu của chính sách Debian nhưng không phải POSIX)).

Tất cả các hệ thống trong phạm vi trên unix.stackexchange.com đều có POSIX sh ở đâu đó. Hầu hết trong số họ có một /bin/sh(bạn có thể tìm thấy những thư mục rất hiếm không có /binthư mục nhưng có lẽ bạn không quan tâm đến điều đó), và đó thường là shtrình thông dịch POSIX (và trong một số trường hợp hiếm hoi là vỏ Bourne (không chuẩn) ).

Nhưng shlà trình thông dịch shell duy nhất có thể thực thi mà bạn có thể chắc chắn tìm thấy trên một hệ thống. Đối với các shell khác, bạn có thể chắc chắn rằng các bản phân phối macOS, Cygwin và hầu hết các GNU / Linux sẽ có bash. Các hệ điều hành có nguồn gốc từ SYSV (Solaris, AIX ...) thường sẽ có ksh88, có thể là ksh93. OpenBSD, MirOS sẽ có đạo hàm pdksh. macOS sẽ có zsh. Nhưng trong số đó, sẽ không có gì đảm bảo. Không đảm bảo dù là bashbất kỳ hoặc bất kỳ vỏ nào khác sẽ được cài đặt trong /binhoặc ở nơi khác (thường được tìm thấy trong /usr/local/binBSD khi được cài đặt chẳng hạn). Và tất nhiên không có gì đảm bảo phiên bản shell sẽ được cài đặt.

Lưu ý rằng đó #! /path/to/executablekhông phải là một quy ước , đó là một tính năng của tất cả các hạt nhân giống Unix (được giới thiệu vào đầu những năm 80 bởi Dennis Ritchie ) cho phép thực thi các tệp tùy ý bằng cách chỉ định đường dẫn của trình thông dịch trong dòng đầu tiên bắt đầu bằng #!. Nó có thể là bất kỳ thực thi.

Khi bạn thực thi một tệp có dòng đầu tiên bắt đầu #! /some/file some-optional-arg, kernel sẽ kết thúc thực thi /some/filevới some-optional-arg, đường dẫn của tập lệnh và các đối số ban đầu là đối số. Bạn có thể thực hiện dòng đầu tiên #! /bin/echo testđể xem những gì đang xảy ra:

$ ./myscript foo
test ./myscript foo

Khi bạn sử dụng /bin/sh -thay vì /bin/echo test, kernel sẽ thực thi /bin/sh - ./myscript foo, shdiễn giải mã nội dung được lưu trữ myscriptvà bỏ qua dòng đầu tiên đó như là một nhận xét (bắt đầu bằng #).


Ally Có lẽ hệ thống duy nhất hiện nay mà bất kỳ ai trong chúng ta sẽ bắt gặp một hệ thống /bin/shdựa trên vỏ Bourne là Solaris 10. Solaris là một trong số ít các Unice quyết định giữ vỏ Bourne ở đó để tương thích ngược ( shngôn ngữ POSIX không hoàn toàn tương thích ngược với vỏ Bourne) và (ít nhất là cho các triển khai máy tính để bàn và máy chủ đầy đủ) có POSIX shở nơi khác (trong /usr/xpg4/bin/sh, dựa trên ksh88), nhưng điều đó đã thay đổi trong Solaris 11, /bin/shgiờ là ksh93. Những người khác chủ yếu là không còn tồn tại.

² Các /bin/shcủa hệ điều hành MacOS / X sử dụng để đượczsh , nhưng sau đó chuyển sang bash. Đây không phải zshlà trọng tâm chính được sử dụng làm shtriển khai POSIX . shChế độ của nó chủ yếu là để có thể nhúng hoặc gọi ( source) shmã POSIX trong zshcác tập lệnh

Gần đây, @schily đã mở rộng lớp vỏ OpenSolaris (dựa trên lớp vỏ SVR4, dựa trên lớp vỏ Bourne) để tuân thủ POSIX, được gọi boshnhưng tôi không biết rằng nó đã được sử dụng trên bất kỳ hệ thống nào. Cùng với ksh88đó làm cho nó trở thành một vỏ tương thích POSIX thứ hai dựa trên mã của vỏ Bourne

4 Trong các phiên bản cũ hơn, bạn cũng có thể sử dụng mkshhoặc lkshhóa thân POSIX hơn . Đó là lớp vỏ MirOS (trước đây là MirBSD) dựa trên pdksh, bản thân nó dựa trên lớp vỏ Forsyth (một cách tái hiện khác của lớp vỏ Bourne))


Điều nhỏ nhặt (về mã shell giữa câu trả lời): Bạn có nên sử dụng ngay exec sh "$0" "$@"sau khi cài đặt PATHkhông? Điều đó sẽ nhận shtừ đúng nơi, tôi sẽ nghĩ.
Kusalananda

1
@Kusalananda, điều đó sẽ hoạt động nhưng rủi ro hơn vì chúng ta có thể kết thúc trong một vòng lặp vô tận nếu có gì đó không ổn (như sh với quyền sai, được sửa đổi ...). Dù sao, phần còn lại là dành riêng cho Solaris 10, vì vậy chúng tôi cũng có thể mã hóa mọi thứ kể cả nội dung $PATH.
Stéphane Chazelas

Bất kỳ trích dẫn nào cho OSX sử dụng ksh làm vỏ POSIX của nó. Shell mặc định của nó được sử dụng là tcsh nhưng tôi không nhớ bash không được sử dụng đặc biệt là Korn Shell không phải là nguồn mở cho đến khi OSX xuất hiện
user151019

1
@Mark, tôi không nói OSX đã từng sử dụng ksh. Tôi đã nói nó từng là zsh và họ đã chuyển sang bash (một bản bash đặc biệt).
Stéphane Chazelas

1
@fpmurphy, nếu bạn xem các phiên bản đầu tiên, bash đã đứng về phía ksh ở bất cứ nơi nào ksh không tương thích với vỏ Bourne. Mặc dù bạn phải đợi cho đến bash2 để có cùng cấp độ tính năng như ksh88, bash ban đầu đã có một số tiện ích mở rộng của ksh như $(...), chế độ emacs / vi, mở rộng tilde / brace (những cái ban đầu từ csh), fc, typet, bí danh , cú pháp hàm kiểu ksh ...
Stéphane Chazelas

8

Có, bạn có thể sử dụng #!/bin/shtrong một tập lệnh bởi vì /bin/sh(hy vọng) được cung cấp cho các hệ thống như vậy, thường là thông qua một liên kết thuộc loại nào đó khiến bashhành vi (ít nhiều) giống như shsẽ xảy ra. Đây là một hệ thống Centos7, ví dụ, liên kết shđến bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

Bạn cũng có thể sử dụng #!/bin/bashnếu bạn chỉ viết một bashtập lệnh cho hệ thống đó và muốn sử dụng bashcác tính năng. Tuy nhiên, kịch bản như vậy sẽ bị ảnh hưởng từ vấn đề tính di động, ví dụ trên OpenBSD nơi bashduy nhất được cài đặt nếu quản trị viên có những rắc rối để cài đặt nó (Tôi không) và sau đó nó được cài đặt để /usr/local/bin/bash, không /bin/bash. Một #!/bin/shtập lệnh POSIX nghiêm ngặt nên dễ mang theo hơn.


Lưu ý điều này: "Khi được gọi là sh, Bash vào chế độ POSIX sau khi đọc các tệp khởi động." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn Jackman

2
Khi tôi viết tập lệnh cho máy chủ RHEL trong công việc của mình, tôi sử dụng #!/bin/bashchính xác để tôi có thể tận dụng các tính năng không phải POSIX.
Monty Harder

@MontyHarder IIRC trên RHEL /bin/shđó là một liên kết tượng trưng bash, điều đó có đúng không? Mặc dù vậy, tôi biết chắc chắn về CentOS.
Sergiy Kolodyazhnyy

1
@SergiyKolodyazhnyy Vâng, trên máy chủ của RHEL tôi vừa kiểm tra, đó là một liên kết tượng trưng đến bash. Nhị phân biết tên được sử dụng để gọi nó và khi nó được gọi là shBourne trường học cũ sh.
Monty Harder

6

Bạn đã hỏi

Có đúng không khi đặt nhận xét #! / bin / sh trong các tập lệnh shell được viết bằng các bản phân phối Ubuntu?

Câu trả lời phụ thuộc vào những gì bạn viết trong kịch bản shell.

  • Nếu bạn sử dụng nghiêm ngặt các tập lệnh tuân thủ POSIX di động và không sử dụng bất kỳ lệnh cụ thể nào của bash, thì bạn có thể sử dụng /bin/sh.

  • Nếu bạn biết rằng bạn chỉ sử dụng tập lệnh trên máy có bash và bạn muốn sử dụng cú pháp dành riêng cho bash, thì bạn nên sử dụng tập lệnh/bin/bash

  • Nếu bạn muốn chắc chắn rằng tập lệnh sẽ hoạt động trên một loại máy unix, thì bạn chỉ nên sử dụng cú pháp tuân thủ POSIX và/bin/sh

  • Nếu bạn thường xuyên sử dụng vỏ khác (ví dụ ksh , zsh hoặc tcsh ), và muốn sử dụng cú pháp mà trong kịch bản của bạn, sau đó bạn nên sử dụng trình biên dịch thích hợp (như /bin/ksh93, /bin/zshhoặc /bin/tcsh)


3

Các "#!" bình luận không phải lúc nào cũng sử dụng /bin/bashhoặc /bin/sh. Nó chỉ liệt kê bất cứ điều gì trình thông dịch nên là, không chỉ cho kịch bản shell. Ví dụ kịch bản python của tôi thường bắt đầu bằng #!/usr/bin/env python.

Bây giờ sự khác biệt giữa #!/bin/sh#!/bin/bash/bin/shkhông phải lúc nào cũng là một liên kết tượng trưng đến /bin/bash. Thường xuyên nhưng không phải luôn luôn. Ubuntu là một ngoại lệ đáng chú ý ở đây. Tôi đã thấy các tập lệnh hoạt động tốt trên CentOS nhưng không thành công trên Ubuntu vì tác giả đã sử dụng cú pháp cụ thể bash với #!/bin/sh.


1

Xin lỗi vì đã đổ một ít nước lạnh vào tất cả những câu trả lời tuyệt vời /bin/shcó trong tất cả các hệ thống Unix - nó có mặt, ngoại trừ trong hệ thống Unix được sử dụng nhiều nhất mọi thời đại: Android.

Android có vỏ của nó /system/bin/shvà thường không có cách nào để tạo /bin/shliên kết, ngay cả trên hệ thống đã được root (do cách hệ thống bị khóa bằng cách sử dụng bộ giới hạn selinux và khả năng (7)).

Đối với những người sẽ nói rằng Android không tuân thủ POSIX: hầu hết các bản phân phối Linux và BSD. Và sự tồn tại của /bin/shvới đường dẫn này không bắt buộc theo tiêu chuẩn :

Các ứng dụng cần lưu ý rằng tiêu chuẩn PATHcho shell không thể được coi là /bin/shhoặc /usr/bin/sh, và nên được xác định bằng cách thẩm vấn PATHtrả lại bởi getconf PATH, đảm bảo rằng tên đường dẫn được trả về là tên đường dẫn tuyệt đối chứ không phải là vỏ được tích hợp.


Mặc dù tất cả các hệ thống cố gắng tuân thủ POSIX đều có nhiều lỗi tuân thủ (bao gồm cả các lỗi được chứng nhận), Android (và hầu hết các hệ thống nhúng khác như bộ định tuyến hoặc HĐH bóng đèn của bạn) không có ý định tuân thủ POSIX. Android không có chủ đề ở đây trừ khi có giao diện POSIX.
Stéphane Chazelas

@Christopher, cái getconfnào? Ví dụ, trên Solaris 11.4, đó có phải là một trong /usr/binkhông? Một trong /usr/xpg4/bin(cho tuân thủ SUSv2), một trong /usr/xpg6/bin(cho tuân thủ SUSv3)? /usr/xpg7/bin(đối với SUSv4)?
Stéphane Chazelas

@ StéphaneChazelas nếu chúng ta phán đoán ý định, tôi nghĩ rằng tôi có thể dễ dàng tìm ra một số trích dẫn của Linus Torvalds hoặc Theo de Raadt về hiệu ứng mà họ không quan tâm nhiều về POSIX ;-) Và hầu hết các hệ thống nhúng đều dựa trên linux + busybox, hầu như không phù hợp với POSIX hơn hệ thống tương tự Unix điển hình. Và a) android không thực sự là một hệ thống "nhúng" và b) một hệ thống Android có thể được thực hiện theo chuẩn POSIX mà không cần có vỏ trong /bin/sh
mosvy

1
@mosvy, những gì bạn nói hầu hết là đúng. Nhưng Torvalds chỉ có thể nói cho nhân Linux. Chet Ramey quan tâm đến việc tuân thủ POSIX đối với bash, RedHat quan tâm đến việc tuân thủ POSIX (họ tài trợ cho nhóm Austin và ngồi trong các cuộc họp nhóm của họ, họ duy trì rất nhiều phần mềm GNU). Ý tưởng là POSIX là tiêu chuẩn duy nhất mà hầu hết các hệ thống giống Unix nhìn vào. Người dùng quan tâm đến việc tuân thủ POSIX vì nó giúp phần mềm di động dễ dàng hơn với các hệ thống khác nhau. Nó không lý tưởng nhưng tốt hơn là không có gì. Android có API lập trình riêng, POSIX không thực sự đáng lo ngại ở đó.
Stéphane Chazelas
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.