Есть ли команда для запуска скрипта в соответствии со строкой shebang?

Если я хочу выполнить bash-скрипт, для которого не установлено разрешение на выполнение, я могу сделать:

bash script.sh

Что я должен использовать вместо bash если скрипт не исполняемый и я не знаю правильный интерпретатор? Есть ли команда, которая ищет интерпретатор из строки shebang и выполняет сценарий вместе с ним?

3 ответа

Решение

Ага. Это называется 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)

Это упоминается в документации Perl:

Если #! строка не содержит ни слова "perl", ни слова "indir", программа, названная в честь #! выполняется вместо интерпретатора Perl. Это немного странно, но это помогает людям на машинах, которые не делают #! потому что они могут сообщить программе, что их SHELL - /usr/bin/perl, и Perl затем отправит программу нужному для них интерпретатору.

Сценарии не обязательно имеют шебанг

Если скрипт был запущен от переводчика, Вы не можете быть уверены, что он имеет шебанг вообще. Скрипты, запускаемые из интерпретатора, не нуждаются в шебанге, если вы вызываете интерпретатор для запуска кода.

Таким образом, ответ - нет, нет команды, которая бы точно знала, на каком языке (интерпретаторе) запускать скрипт. Однако вы всегда можете заглянуть внутрь сценария и посмотреть, есть ли у него шебанг, чтобы узнать.

Правила вкратце:

  1. Когда вы запускаете скрипт, вызов интерпретатора всегда отменяет возможные shebang, исполняемые или нет, shebang или нет.
  2. Если скрипт не исполняется и запускается из интерпретатора, сценарий не нуждается в шебанге.
  3. Если скрипт запускается без вызова интерпретатора, ему нужен (и использует) шебанг, чтобы узнать, какой интерпретатор вызывать, и он должен быть исполняемым, чтобы иметь "разрешение" на вызов интерпретатора из своего шебанга.

Однако, если в сценарии нет шебанга, в сценарии нет (прямой *) информации, указывающей, какой интерпретатор использовать.

Было сказано, что

Конечно, вы всегда можете написать скрипт-обертку, чтобы попытаться выяснить, есть ли у скрипта шебанг, и прочитать интерпретатор из него, а затем запустить его из найденного интерпретатора.

Пример

#!/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")
  • Сохранить как tryrun в $PATH (например ~/binсоздайте каталог, если он не существует, выйдите из системы и снова войдите в него, сделайте его исполняемым. Затем работает:

    tryrun /path/to/nonexecutablescript
    

    вызывает (проверял) правильный интерпретатор на моем неисполнимом python а также bash скрипты.

объяснение

  • Скрипт просто читает первую строку скрипта, удаляет #! и использует остальное для вызова переводчика.
  • Если он не может вызвать действительного переводчика, он вызовет PermissionError или FileNotFoundError,

Заметка

Расширение (.sh, .py и т.д.) не играет никакой роли при определении соответствующего интерпретатора в Linux.


(* Конечно, можно разработать "умный" алгоритм предположения для определения синтаксиса из кода.)

Вы можете достичь этого с помощью скрипта, подобного этому:

#!/bin/bash

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

Таким образом:

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

Я рекомендую не делать этого. Разрешения есть по причине. Это программа для подрыва разрешений.

Обратите внимание, что обработка shebang - это функция ядра (в исходном коде Linux - fs/binfmt_script.c). По сути, процесс, вызывающий скрипт напрямую, не знает о #! - ядро ​​использует его для определения необходимости запуска интерпретатора.

Другие вопросы по тегам