Tại sao hành vi của cú pháp `#!` Không được chỉ định bởi POSIX?


17

Từ trang Ngôn ngữ lệnh Shell của đặc tả POSIX:

Nếu dòng đầu tiên của tệp lệnh shell bắt đầu bằng ký tự "#!", Kết quả không được chỉ định.

Tại sao hành vi của #!POSIX không được chỉ định? Tôi thấy khó hiểu rằng một cái gì đó rất di động và được sử dụng rộng rãi sẽ có một hành vi không xác định.


1
Các tiêu chuẩn để lại những điều không xác định để không ràng buộc việc thực hiện với các hành vi cụ thể. Ví dụ: "đăng nhập" là "Hoạt động không xác định mà người dùng có quyền truy cập vào hệ thống."
Kusalananda

2
Vì POSIX không chỉ định đường dẫn thực thi, nên một dòng shebang vốn không thể mang theo được; Tôi không chắc chắn sẽ đạt được nhiều bằng cách chỉ định nó bất kể.
Michael Homer

1
@MichaelHomer, chắc chắn không? Tiêu chuẩn có thể chỉ định rằng dòng chứa một đường dẫn để sử dụng cho trình thông dịch, thậm chí không cần nói đường dẫn đó là gì.
ilkkachu

1
@HaroldFischer Ngoại trừ nó không được giải thích bởi shell, nó được giải thích bởi kernel OS (được thực hiện ít nhất trên Linux, có thể thực sự vô hiệu hóa hỗ trợ này trong thời gian xây dựng) hoặc bất kỳ thư viện nào thực hiện exec()chức năng này. Vì vậy, kiểm tra đối với nhiều vỏ không thực sự cho bạn biết nó di động như thế nào.
Austin Hemmelgarn

2
@HaroldFischer Hơn nữa, ngay cả trong số các HĐH tuân thủ POSIX, hành vi không nhất quán. Linux và macOS hoạt động khác nhau: Linux không token hóa hoàn toàn dòng shebang theo không gian. macOS không cho phép trình thông dịch tập lệnh trở thành tập lệnh khác. Đồng thời xem en.wikipedia.org/wiki/Shebang_(Unix)#Portability
jamesdlin 18/12/18

Câu trả lời:


21

Tôi nghĩ chủ yếu vì:

  • hành vi khác nhau rất nhiều giữa thực hiện. Xem https://www.in-ulm.de/~mascheck/various/shebang/ để biết tất cả các chi tiết.

    Tuy nhiên, hiện tại nó có thể chỉ định một tập hợp con tối thiểu của hầu hết các triển khai giống Unix: như #! *[^ ]+( +[^ ]+)?\n(chỉ có các ký tự từ ký tự tên tệp di động được đặt trong một hoặc hai từ đó) trong đó từ đầu tiên là đường dẫn tuyệt đối đến một tệp thực thi gốc, điều này không phải là quá dài và hành vi không được chỉ định nếu tệp thực thi là setuid / setgid và việc triển khai được xác định cho dù đường dẫn trình thông dịch hoặc đường dẫn kịch bản được truyền argv[0]cho trình thông dịch.

  • POSIX không chỉ định đường dẫn thực thi nào. Một số hệ thống có các tiện ích tiền POSIX trong /bin/ /usr/binvà có các tiện ích POSIX ở một nơi khác (như trên Solaris 10 có /bin/shvỏ Bourne và một POSIX nằm trong /usr/xpg4/bin; Solaris 11 đã thay thế nó bằng ksh93, tương thích POSIX hơn, nhưng hầu hết các hệ thống khác các công cụ trong /binvẫn là những công cụ không phải là POSIX cổ đại). Một số hệ thống không phải là POSIX nhưng có chế độ / mô phỏng POSIX. Tất cả POSIX yêu cầu là có một môi trường được ghi lại trong đó một hệ thống hành xử POSIXly.

    Xem Windows + Cygwin chẳng hạn. Trên thực tế, với Windows + Cygwin, she-bang được vinh danh khi một tập lệnh được gọi bởi một ứng dụng cygwin, nhưng không phải bởi một ứng dụng Windows gốc.

    Vì vậy, ngay cả khi POSIX chỉ định cơ chế shebang, nó không thể được sử dụng để viết tập lệnh POSIX sh/ sed/ awk... (cũng lưu ý rằng cơ chế shebang không thể được sử dụng để viết tin cậy sed/ awktập lệnh vì nó không cho phép vượt qua tùy chọn kết thúc đánh dấu).

Bây giờ thực tế là nó không được chỉ định không có nghĩa là bạn không thể sử dụng nó (vâng, nó nói rằng bạn không nên bắt đầu dòng đầu tiên #!nếu bạn mong đợi nó chỉ là một nhận xét thông thường chứ không phải là một tiếng nổ), nhưng POSIX không bảo đảm nếu bạn làm như vậy.

Theo kinh nghiệm của tôi, việc sử dụng shebang mang lại cho bạn sự đảm bảo về tính di động hơn là sử dụng cách viết các kịch bản shell của POSIX: bỏ qua cô ấy, viết kịch bản theo shcú pháp POSIX và hy vọng rằng bất cứ điều gì gọi kịch bản đều gọi ra một quy tắc POSIX shtrên đó, đó là tốt nếu bạn biết tập lệnh sẽ được gọi trong môi trường phù hợp bằng công cụ phù hợp nhưng không thì khác.

Bạn có thể phải làm những việc như:

#! /bin/sh -
if : ^ false; then : fine, POSIX system by default
else
  # cover Solaris 10 or older. ": ^ false" returns false
  # in the Bourne shell as ^ is an alias for | there for
  # compatibility with the Thomson shell.
  PATH=`getconf PATH`:$PATH; export PATH
  exec /usr/xpg4/bin/sh - "$0" ${1+"$@"}
fi
# rest of script

Nếu bạn muốn có thể mang theo Windows + Cygwin, bạn có thể phải đặt tên cho tệp của mình bằng một .bathoặc một .ps1phần mở rộng và sử dụng một số mẹo tương tự cho cmd.exehoặc powershell.exeđể gọi Cygwin shtrên cùng một tệp.


Thật thú vị, từ vấn đề 5 : "Cấu trúc #! Được dành riêng cho việc triển khai muốn cung cấp tiện ích mở rộng đó. Một ứng dụng di động không thể sử dụng #! Là dòng đầu tiên của tập lệnh shell; nó có thể không được hiểu là một nhận xét."
muru

@muru Nếu tập lệnh thực sự di động, trên hệ thống POSIX thực sự chạy POSIX sh, nó sẽ không cần dòng hashbang vì nó sẽ được POSIX thực thi sh.
Kusalananda

1
@Kusalananda đó chỉ đúng nếu execlphay execvpđược sử dụng, phải không? Nếu tôi sử dụng execve, nó sẽ dẫn đến ENOEXEC?
muru

9

[T] hành vi của anh ta có vẻ phù hợp giữa tất cả các vỏ khiếu nại POSIX. Tôi không thấy sự cần thiết của phòng ngọ nguậy ở đây.

Bạn không nhìn đủ sâu.

Trở lại những năm 1980, cơ chế này không được chuẩn hóa trên thực tế. Mặc dù Dennis Ritchie đã thực hiện nó, nhưng việc thực hiện đó đã không đến được với công chúng ở phía AT & T của vũ trụ. Nó thực sự chỉ có sẵn công khai và được biết đến trong BSD; với các tập lệnh shell thực thi không có sẵn trên AT & T Unix. Do đó, không hợp lý để chuẩn hóa nó. Tình trạng của vấn đề được minh họa bởi tài liệu đương đại này, một trong nhiều vấn đề như sau:

Lưu ý rằng BSD cho phép các tệp bắt đầu #! interpreterđược thực thi trực tiếp, trong khi SysV chỉ cho phép các tệp a.out được thực thi trực tiếp. Điều này có nghĩa là một thể hiện của một trong các exec…()thói quen trong chương trình BSD có thể phải được thay đổi theo SysV để thực thi trình thông dịch (theo cách thức /bin/sh) cho chương trình đó.
- Stephen Frede (1988). "Lập trình trên Hệ thống X Phát hành Y". Bản tin nhóm người dùng hệ thống Unix của Úc . Tập 9. Số 4. p. 111.

Một điểm quan trọng ở đây là bạn đang xem shell, trong khi sự tồn tại của các kịch bản shell thực thi thực sự là một vấn đề cho các exec…()hàm. Các shell nào bao gồm các tiền thân của cơ chế tập lệnh thực thi, vẫn được tìm thấy trong một số shell ngay cả ngày nay (và hiện tại cũng được ủy quyền cho exec…p()tập hợp con của các hàm), và có phần sai lệch. Những gì tiêu chuẩn cần giải quyết trong vấn đề này là làm thế nào exec…()trên một kịch bản diễn giải hoạt động, và tại thời điểm POSIX ban đầu được tạo ra, nó chỉ đơn giản là không hoạt động ở vị trí đầu tiên trong một phần chính của phổ hệ điều hành đích .

Một câu hỏi phụ là tại sao điều này chưa được tiêu chuẩn hóa, đặc biệt là khi cơ chế số ma thuật cho các phiên dịch viên kịch bản đã đến với công chúng ở phía AT & T của vũ trụ và đã được ghi nhận exec…()trong Định nghĩa giao diện hệ thống 5 , vào đầu những năm 1990 :

Một tệp thông dịch bắt đầu bằng một dòng của mẫu

#! tên đường dẫn [arg]
trong đó pathname là đường dẫn của trình thông dịch và arg là một đối số tùy chọn. Khi bạn execmột tệp thông dịch, hệ thống execsẽ là trình thông dịch được chỉ định.
- exec. System V Interface Definition . Tập 1. 1991.

Thật không may, hành vi này vẫn còn gần như khác biệt như trong những năm 1980 và không có hành vi thực sự phổ biến để chuẩn hóa. Một số Unice (ví dụ nổi tiếng là HP-UX và FreeBSD) không hỗ trợ tập lệnh làm thông dịch viên cho tập lệnh. Cho dù dòng đầu tiên là một, hai hoặc nhiều phần tử được phân tách bằng khoảng trắng khác nhau giữa MacOS (và các phiên bản FreeBSD trước năm 2005) và các phần tử khác. Độ dài đường dẫn được hỗ trợ tối đa khác nhau. và các ký tự nằm ngoài bộ ký tự tên tệp di động POSIX rất khó, như là khoảng trắng hàng đầu và dấu. Điều mà đối số 0, 1 và 2 kết thúc cũng là khó khăn, với sự thay đổi đáng kể giữa các hệ thống. Một số hiện đang tuân thủ POSIX nhưng không-Các hệ thống unix vẫn không hỗ trợ bất kỳ cơ chế nào như vậy và bắt buộc nó sẽ chuyển đổi chúng thành không còn phù hợp với POSIX.

đọc thêm


1

Theo ghi nhận của một số câu trả lời khác, việc triển khai khác nhau. Điều này khiến cho việc chuẩn hóa duy trì khả năng tương thích ngược với các tập lệnh hiện có trở nên khó khăn . Điều này đúng ngay cả đối với các hệ thống POSIX hiện đại. Ví dụ: Linux không token hóa hoàn toàn dòng shebang theo khoảng trắng. macOS không cho phép trình thông dịch tập lệnh trở thành tập lệnh khác.

Đồng thời xem http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability

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.