Чи є команда для запуску сценарію відповідно до його рядка shebang?


46

Якщо я хочу виконати скрипт bash, який не має дозволу на виконання, я можу зробити:

bash script.sh

Що я повинен використовувати замість, bashякщо скрипт не виконується, і я не знаю правильного інтерпретатора? Чи є команда, яка шукає інтерпретатора з рядка shebang і виконує скрипт з ним?


Що не так?
steffen

@steffen Як ти знаєш, про який файл йдеться, це баш сценарій?
муру

Цитата @muru з питання: "Якщо я хочу виконати скрипт bash ..." Більше того (навіть якщо це не bash-скрипт), якщо bash whateverпрацює, навіщо використовувати щось інше? bash доступний практично в кожній системі * ix, тож навіщо турбуватись ...
steffen

1
@steffen Ви прочитали решту запитань? Вони кажуть: "Якщо ... тоді я можу зробити: ..." і "Що я повинен використовувати замість баш, якщо ... я не знаю правильного перекладача ?"
муру

@muru: можливо, я не бачу очевидного. Але якщо рядок file / has / a shebang, як зазначено у запитанні, bash зробить саме те, що вимагається. Як буде перл, відповідно до відповіді нижче. Отже, яка перевага від використання bash?
steffen

Відповіді:


67

Так. Це називається 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 потім направить програму правильному для них інтерпретатору.


40
Ну, це просто брудно.
струнка

1
Чи працює розширення файлу .js?
Pysis

1
Також те, що машини не роблять #!. Я, здається, зараз кілька і більше, і не відчував цієї проблеми.
Pysis

1
Гаразд, саме ваш приклад, схоже, виділив багато розширень файлів, а не демонстрував декілька рядків shebang з файлів, і, мабуть, я припустив, що саме так спрацювало його передбачення.
Pysis

2
Мені подобається, як по- man perlrunсмішному визнає, що це "трохи химерно" :). Я думаю, що до цього слід ставитися як до цікавості, спрямованої на оточення, що не належать до UNIX, та дуже старі версії UNIX.
тонкий

25

У сценаріїв не обов'язково є шебанг

Якщо сценарій був запущений з інтерпретатора, Ви не можете бути впевнені , що він має притон взагалі . Сценарії, запущені від інтерпретатора, не потребують шебанг , якщо ви зателефонуєте перекладачеві для запуску коду.

Відповідь - ні, немає команди, яка б точно дізналася, якою є мова (інтерпретатор), з якою слід запускати скрипт. Однак ви завжди можете зазирнути в сценарій і побачити, чи є у нього шебанг, щоб це дізнатися.

Коротше кажучи правила:

  1. Під час запуску сценарію виклик перекладача завжди перекриває можливі шебанги, виконувані чи ні, шебанг чи ні.
  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сценаріях.

Пояснення

  • Сценарій просто зчитує перший рядок сценарію, видаляє #!та використовує решту для виклику перекладача.
  • Якщо не вдасться викликати дійсного перекладача, він піднімає або a, PermissionErrorабо a FileNotFoundError.

Примітка

Розширення ( .sh, і .pyт.д.) не має ніякого значення в визначенні відповідного перекладача на Linux.


(* Звичайно, можна розробити "розумний" алгоритм відгадки для визначення синтаксису з коду.)


Гаразд, це означає, що хоча Linux десь реалізовано видобуток shebang (щоб він міг вибрати правильний інтерпретатор для виконуваних srcipts), він не надається як окрема стандартна команда.
Айвар

@Aivar витягнути шебанг - це не проблема, але запустити код без нього цілком можливо.
Яків Влійм

@Aivar Ах, я бачу, що ти маєш на увазі. Якщо сценарій виконується і працює без мови в команді, скрипт викликає інтерпретатора, а не навпаки.
Яків Влійм

1
@JacobVlijm Я б не сказав, що "скрипт викликає інтерпретатора", як "ядро Linux приймає рядок shebang, щоб визначити, який інтерпретатор викликати під час виконання сценарію".
Paŭlo Ebermann

@ PaŭloEbermann Дякую! Правда звичайно. Ядро піклується про всю процедуру в будь-якому випадку, але образно, і я думаю, що краще для розуміння, це сказати, що сценарію "дозволено" піклуватися про те, що інтерпретатор викликати (і насправді це робити). Не впевнений у формулюванні, але я хотів би описати це так, ніби ініціатива на сценарії, в той час як ядро ​​насправді виконує цю роботу.
Яків Влійм

6

Ви можете досягти цього за допомогою такого сценарію:

#!/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). По суті, процес, що викликає скрипт, безпосередньо не знає про це #!- ядро ​​використовує його, щоб визначити, що йому потрібно запустити інтерпретатор.


2
Я завжди вважав, що це функція оболонки, а не ядра. Сьогодні дізналися щось нове.
boatcoder

1
@boatcoder - Оскільки ви зацікавлені, додали посилання на те, де вихідний код Linux обробляє його.
стрункий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.