Có một lệnh để chạy một kịch bản theo dòng shebang của nó?


46

Nếu tôi muốn thực thi tập lệnh bash không có quyền thực thi, tôi có thể thực hiện:

bash script.sh

Tôi nên sử dụng cái gì thay vì bashnếu tập lệnh không thực thi được và tôi không biết trình thông dịch chính xác? Có một lệnh tìm kiếm trình thông dịch từ dòng shebang và thực thi kịch bản với nó?


Có gì sai bash bash?
steffen

@steffen làm thế nào để bạn biết các tập tin trong câu hỏi là một tập lệnh bash?
muru

@muru trích dẫn từ Câu hỏi: "Nếu tôi muốn thực thi tập lệnh bash ..." Ngoài ra (ngay cả khi đó không phải là tập lệnh bash), nếu bash whateverhoạt động, tại sao lại sử dụng nội dung khác? bash có sẵn trên hầu hết mọi hệ thống * ix, vậy tại sao phải bận tâm ...
steffen

1
@steffen bạn đã đọc phần còn lại của câu hỏi chưa? Họ nói: "Nếu ... thì tôi có thể làm: ..." và "Tôi nên sử dụng gì thay vì bash nếu ... tôi không biết người phiên dịch chính xác ?"
muru

@muru: có lẽ tôi không thấy rõ ràng. Nhưng nếu tệp / has / a shebang, như đã nêu trong câu hỏi, bash sẽ thực hiện chính xác những gì được yêu cầu. Như sẽ perl, theo câu trả lời dưới đây. Vậy lợi thế của việc không sử dụng bash là gì?
steffen

Câu trả lời:


67

Vâng. Nó được gọi là perl:

perl foo.bash    # works
perl foo.lua     # works
perl foo.clisp   # works
perl foo.csh     # works
perl foo.php     # works
perl foo.gnuplot # works (no arguments)
perl foo.pl      # works (obviously)
perl foo.py      # works
perl foo.sh      # works
perl foo.tcl     # works
perl foo.rb      # works
perl foo.nodejs  # works
perl foo.r       # works
perl foo.oct     # works
perl foo.csharp  # works (no arguments)

Điều này được đề cập trong tài liệu của Perl :

Nếu #!dòng không chứa từ "perl" cũng không phải từ "indir", chương trình được đặt tên theo sau #!được thực thi thay vì trình thông dịch Perl. Điều này hơi kỳ quái, nhưng nó giúp mọi người trên các máy không làm được #!, bởi vì họ có thể nói với một chương trình rằng SHELL của họ là / usr / bin / perl, và sau đó Perl sẽ gửi chương trình tới trình thông dịch chính xác cho họ.


40
Chà, thật là bẩn.
mỏng

1
Phần mở rộng tập tin .jscũng hoạt động?
Pysis

1
Ngoài ra, những gì máy móc không làm #!. Bây giờ tôi dường như còn ít hơn và chưa gặp vấn đề này.
Pysis

1
Ok, đó chỉ là ví dụ của bạn làm nổi bật rất nhiều phần mở rộng tệp, thay vì hiển thị một số dòng shebang từ các tệp và tôi đoán rằng tôi cho rằng đó là cách dự đoán của nó hoạt động.
Pysis

2
Tôi thích cách man perlrunngượng ngùng thừa nhận rằng nó "hơi kỳ quái" :). Tôi nghĩ rằng điều này nên được coi là một sự tò mò nhắm vào các môi trường không phải là UNIX và các phiên bản rất cũ của UNIX.
mỏng

25

Kịch bản không nhất thiết phải có shebang

Nếu kịch bản được chạy từ người phiên dịch, Bạn không thể chắc chắn nó có công việc ở tất cả . Các tập lệnh, chạy từ trình thông dịch không cần shebang , nếu bạn gọi trình thông dịch để chạy mã.

Do đó, câu trả lời là không, không có lệnh nào sẽ tìm ra chắc chắn ngôn ngữ (trình thông dịch) để chạy tập lệnh là gì. Tuy nhiên, bạn luôn có thể nhìn vào bên trong tập lệnh và xem nó có shebang để tìm hiểu không.

Các quy tắc ngắn gọn:

  1. Khi bạn chạy tập lệnh, gọi trình thông dịch luôn ghi đè các shebang có thể, có thực thi được hay không, shebang hay không.
  2. Nếu không thể thực thi và chạy từ trình thông dịch, tập lệnh không cần shebang.
  3. Nếu tập lệnh được chạy mà không gọi trình thông dịch trước, nó cần (và sử dụng) shebang để tìm hiểu trình thông dịch nào cần gọi nó cần được thực thi để có "quyền" gọi trình thông dịch từ shebang.

Tuy nhiên, nếu tập lệnh không có shebang, thì không có thông tin (trực tiếp *) bên trong tập lệnh để cho biết trình thông dịch nào sẽ sử dụng.

Có nói rằng

Tất nhiên, bạn luôn có thể viết một tập lệnh bao bọc để cố gắng tìm hiểu xem tập lệnh có shebang hay không và đọc trình thông dịch từ đó, sau đó chạy nó từ trình thông dịch tìm thấy.

Một ví dụ

#!/usr/bin/env python3
import subprocess
import sys

args = sys.argv[1:]; script = args[0]

try:
    lang = open(script).readlines()[0].replace("#!", "").strip().split()[-1]
    cmd = [lang, script]+args[1:]
    subprocess.call(cmd)
except (PermissionError, FileNotFoundError, IndexError):
    print("No valid shebang found")
  • Lưu nó như tryruntrong $PATH(ví dụ: ~/bintạo thư mục nếu nó không tồn tại, đăng xuất và đăng nhập lại), làm cho nó thực thi được . Sau đó chạy:

    tryrun /path/to/nonexecutablescript

    gọi (đã kiểm tra) trình thông dịch chính xác trên các tập lệnh pythonbashtập lệnh không thực thi của tôi .

Giải trình

  • Kịch bản chỉ cần đọc dòng đầu tiên của tập lệnh, loại bỏ #!và sử dụng phần còn lại để gọi trình thông dịch.
  • Nếu nó không gọi được một thông dịch viên hợp lệ, nó sẽ tăng a PermissionErrorhoặc a FileNotFoundError.

Ghi chú

Phần mở rộng ( .sh, .pyv.v.) không có vai trò gì trong việc xác định trình thông dịch phù hợp trên Linux.


(* Tất nhiên có thể phát triển thuật toán đoán "thông minh" để xác định cú pháp từ mã.)


OK, điều đó có nghĩa là mặc dù Linux đã trích xuất shebang ở đâu đó (để nó có thể chọn trình thông dịch chính xác cho srcipts thực thi), nhưng nó không được cung cấp như một lệnh tiêu chuẩn độc lập.
Aivar

@Aivar trích xuất shebang không phải là vấn đề, nhưng chạy mã mà không có nó là hoàn toàn có thể.
Jacob Vlijm

@Aivar Ah, tôi hiểu ý của bạn. Nếu tập lệnh có thể thực thi và chạy mà không có ngôn ngữ trong lệnh, tập lệnh sẽ gọi trình thông dịch, không phải là cách khác.
Jacob Vlijm

1
@JacobVlijm Tôi sẽ không nói "tập lệnh gọi trình thông dịch", giống như "nhân Linux lấy dòng shebang để tìm ra trình thông dịch nào sẽ gọi khi thực thi tập lệnh".
Paŭlo Ebermann

@ PaŭloEbermann Cảm ơn! Đúng tất nhiên. Hạt nhân chăm sóc toàn bộ quy trình theo bất kỳ cách nào, nhưng theo nghĩa bóng, và tôi nghĩ tốt hơn để hiểu, là nói rằng kịch bản được "cho phép" để quan tâm đến việc gọi trình thông dịch nào (và thực sự làm điều đó). Không chắc chắn về từ ngữ, nhưng tôi muốn mô tả nó như thể sáng kiến ​​nằm trên kịch bản, trong khi kernel thực sự làm việc đó.
Jacob Vlijm

6

Bạn có thể đạt được điều này với một kịch bản như thế này:

#!/bin/bash

copy=/tmp/runner.$$
cp $1 ${copy}
chmod u+x ${copy}
${copy}
rm ${copy}

Do vậy:

$ echo "echo hello" > myscript
$ ./myscript
bash: ./myscript: Permission denied
$ ./runscript myscript 
hello

Tôi khuyên bạn không nên làm điều này. Quyền là có lý do. Đây là một chương trình cho phép lật đổ.

Lưu ý rằng xử lý shebang là một hàm kernel (trong mã nguồn Linux - fs/binfmt_script.c). Về cơ bản, quá trình gọi một tập lệnh trực tiếp không biết về #!- kernel sử dụng nó để tìm ra rằng nó cần khởi chạy một trình thông dịch.


2
Tôi đã luôn luôn cho rằng đó là một chức năng của shell, KHÔNG phải kernel. Đã học được một cái gì đó mới ngày hôm nay.
thuyền viên

1
@boatcoder - Vì bạn quan tâm, đã thêm một liên kết đến nơi mã nguồn Linux xử lý nó.
mỏng
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.