Tại sao không sử dụng shebang vô lối?


24

Có thể có một shebang, thay vì chỉ định đường dẫn đến trình thông dịch, nó có tên của trình thông dịch và để trình bao tìm thấy nó thông qua $ PATH?

Nếu không, có một lý do tại sao?


Câu trả lời:


20

Tra cứu PATH là một tính năng của thư viện C tiêu chuẩn trong không gian người dùng, cũng như các biến môi trường nói chung. Hạt nhân không nhìn thấy các biến môi trường trừ khi nó đi qua một môi trường từ người gọi execveđến tiến trình mới.

Hạt nhân không thực hiện bất kỳ giải thích nào trên đường dẫn trong execve(tùy thuộc vào các chức năng bao bọc như execvpđể thực hiện tra cứu PATH) hoặc trong một shebang (mà ít nhiều định tuyến lại execvecuộc gọi trong nội bộ). Vì vậy, bạn cần đặt đường dẫn tuyệt đối trong shebang¹. Việc triển khai shebang ban đầu chỉ là một vài dòng mã và nó đã không được mở rộng đáng kể kể từ đó.

Trong các phiên bản đầu tiên của Unix, shell đã thực hiện công việc gọi chính nó khi nhận thấy bạn đang gọi một tập lệnh. Shebang đã được thêm vào kernel vì nhiều lý do (tóm tắt lý do của Dennis Ritchie :

  • Người gọi không phải lo lắng liệu chương trình thực thi là tập lệnh shell hay nhị phân riêng.
  • Chính kịch bản chỉ định sử dụng trình thông dịch nào, thay vì người gọi.
  • Nhân sử dụng tên tập lệnh trong nhật ký.

Các shebang không có yêu cầu sẽ yêu cầu tăng kernel để truy cập các biến môi trường và xử lý PATHhoặc để kernel thực thi chương trình không gian người dùng thực hiện tra cứu PATH. Phương thức đầu tiên yêu cầu thêm một lượng phức tạp không cân xứng vào kernel. Phương pháp thứ hai đã có thể với một #!/usr/bin/envshebang .

¹ Nếu bạn đặt một đường dẫn tương đối, nó giải thích tương đối đến thư mục hiện tại của quá trình (không phải là thư mục chứa các kịch bản), đó là hầu như không hữu ích trong một công việc.


2
Không, hạt nhân không yêu cầu một đường dẫn tuyệt đối execvecũng như trong shebang mặc dù nó có ý nghĩa rất nhỏ để có một đường dẫn tương đối trong một shebang.
Stéphane Chazelas

3
Đối với bất kỳ ai tò mò về cách "shebang định tuyến lại lệnh thực thi gọi nội bộ": Đây thực sự là một phần của cơ chế chung để chạy trình thông dịch trên các tệp thực thi cần chúng. Các tệp thực thi ELF được liên kết động được "diễn giải" bởi /lib64/ld-linux-x86-64.so.2(xem lddđầu ra). Linux làm cho nó hoàn toàn chung chung: binfmthỗ trợ (kể từ 2.1.43) cho phép bạn đăng ký các cặp trình thông dịch đường dẫn / ma thuật số hoặc tệp mở rộng. Bạn có thể có lệnh .exegọi PE32 winekhi bạn chạy chúng, lớp Java và các tệp jar gọi java, v.v.
Peter Cordes

#! / usr / bin / env -S [shebang] được yêu cầu cho tôi chạy nút mà không biết đường dẫn của nó (sử dụng nvm - đặt nó ở một vị trí khác với dự kiến ​​ban đầu của tôi).
TamusJRoyce

-S chỉ khả dụng kể từ coreutils 8.30. Xem gitlab.com/gnuwget/wget/commit/ .
Rockdaboot Tim Ruehsen

19

Có nhiều thứ đang diễn ra hơn là bắt mắt. #!các dòng được giải thích bởi nhân Unix hoặc Linux, #!không phải là một khía cạnh của shell. Điều này có nghĩa là PATHkhông thực sự tồn tại tại thời điểm kernel quyết định thực thi cái gì.

Cách phổ biến nhất để đối phó với việc không biết nên chạy chương trình nào, hoặc gọi perltheo kiểu di động hoặc tương tự, là sử dụng #!/usr/bin/env perl. Nhân thực thi /usr/bin/env, kế thừa một PATHbiến môi trường. envphát hiện (trong ví dụ này) perltrong PATHvà sử dụng các execve(2)cuộc gọi hệ thống để có được những hạt nhân để chạy perlthực thi.


4
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0

Việc chuyển đổi sang đường dẫn đầy đủ được thực hiện bởi trình bao (tổng quát hơn: trong không gian người dùng). Nhân mong đợi một tên tệp / đường dẫn mà nó có thể truy cập trực tiếp.

Nếu bạn muốn hệ thống tìm thấy khả năng thực thi của mình bằng cách xem qua biến PATH, bạn có thể viết lại shebang của mình dưới dạng #!/usr/bin/env EXEC.

Nhưng cũng trong trường hợp này, đó không phải là nhân thực hiện tìm kiếm.


1
Việc chuyển đổi sang đường dẫn đầy đủ được thực hiện bởi shell Cảm ơn, mặc dù ... đây có phải là ví dụ minh họa cho điều đó không? Như tôi thấy, shell chỉ đang chạy strace(được chuyển đổi /usr/bin/stracetại một số điểm) với 2 đối số.
Alois Mahdal
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.