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ó 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:
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 execve
cuộ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 :
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ý PATH
hoặ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/env
shebang .
¹ 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.
execve
cũ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.
/lib64/ld-linux-x86-64.so.2
(xem ldd
đầu ra). Linux làm cho nó hoàn toàn chung chung: binfmt
hỗ 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 .exe
gọi PE32 wine
khi bạn chạy chúng, lớp Java và các tệp jar gọi java
, v.v.
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à PATH
khô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 perl
theo 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 PATH
biến môi trường. env
phát hiện (trong ví dụ này) perl
trong PATH
và sử dụng các execve(2)
cuộc gọi hệ thống để có được những hạt nhân để chạy perl
thực thi.
$ 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.
strace
(được chuyển đổi /usr/bin/strace
tại một số điểm) với 2 đối số.