Gibt es einen Befehl zum Ausführen eines Skripts gemäß seiner Shebang-Zeile?

46

Wenn ich ein Bash-Skript ausführen möchte, dessen Ausführungsberechtigung nicht festgelegt ist, kann ich Folgendes tun:

bash script.sh

Was soll ich bashtun, wenn das Skript nicht ausführbar ist und ich den richtigen Interpreter nicht kenne? Gibt es einen Befehl, der den Interpreter von shebang line aus aufruft und das Skript damit ausführt?

Aivar
quelle
Was ist los mit Bash?
steffen
@steffen woher weißt du, dass es sich bei der fraglichen Datei um ein Bash-Skript handelt?
muru
@muru Zitat aus Frage: "Wenn ich ein Bash-Skript ausführen möchte ..." Außerdem (auch wenn es kein Bash-Skript ist), wenn es bash whateverfunktioniert, warum etwas anderes verwenden? bash ist auf nahezu jedes * ix - System zur Verfügung, also warum die Mühe ...
steffen
1
@steffen hast du den rest der frage gelesen? Sie sagen: "Wenn ... dann kann ich tun: ..." und "Was soll ich anstelle von bash verwenden, wenn ... ich den richtigen Interpreter nicht kenne ?"
muru
@muru: Vielleicht sehe ich das Offensichtliche nicht. Aber wenn die Datei / has / eine Shebang-Zeile enthält, wie in der Frage angegeben, wird bash genau das tun, was verlangt wird. Wie wird Perl laut der Antwort unten. Was ist der Vorteil, wenn Sie nicht bash verwenden?
Steffen

Antworten:

67

Ja. Es heißt 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)

Dies wird in der Dokumentation von Perl erwähnt :

Wenn die #!Zeile weder das Wort "perl" noch das Wort "indir" enthält, #!wird anstelle des Perl-Interpreters das nach dem genannte Programm ausgeführt. Das ist etwas bizarr, aber es hilft Leuten auf Maschinen, die es nicht tun #!, weil sie einem Programm mitteilen können, dass ihre SHELL / usr / bin / perl ist, und Perl wird das Programm dann an den richtigen Interpreter für sie senden.

Ole Tange
quelle
40
Nun, das ist nur dreckig.
schlank
1
Funktioniert die Dateierweiterung .jsauch?
Pysis,
1
Auch was Maschinen nicht tun #!. Ich scheine jetzt ein paar zu mehr und habe dieses Problem nicht erfahren.
Pysis,
1
Ok, es ist nur Ihr Beispiel, das eine Menge Dateierweiterungen hervorhebt, anstatt mehrere Shebang-Zeilen aus Dateien zu präsentieren, und ich nehme an, dass die Vorhersage so funktioniert hat.
Pysis
2
Ich mag, wie man perlrunverlegen zugibt, dass es "etwas bizarr" ist :). Ich denke, dies sollte als eine Kuriosität behandelt werden, die sich an Nicht-UNIX-Umgebungen und sehr sehr alte Versionen von UNIX richtet .
Slim
25

Skripte müssen nicht unbedingt einen Wahnsinn haben

Wenn das Skript aus dem Interpreter ausgeführt wurde, können Sie nicht sicher sein , den shebang hat überhaupt . Skripte, die vom Interpreter ausgeführt werden, benötigen den shebang nicht , wenn Sie den Interpreter aufrufen, um den Code auszuführen.

Die Antwort lautet daher "Nein". Es gibt keinen Befehl, der mit Sicherheit herausfindet, in welcher Sprache (mit welchem ​​Interpreter) das Skript ausgeführt werden soll. Sie können jedoch immer in das Drehbuch schauen und sehen, ob es das Zeug dazu hat, es herauszufinden.

Die Regeln in Kürze:

  1. Wenn Sie das Skript ausführen, überschreibt der Aufruf des Interpreters immer mögliche Shebangs, ausführbar oder nicht, Shebang oder nicht.
  2. Wenn es nicht ausführbar ist und vom Interpreter ausgeführt wird, benötigt das Skript kein Problem.
  3. Wenn das Skript ausgeführt wird, ohne zuerst den Interpreter aufzurufen, benötigt (und verwendet) es den Shebang, um herauszufinden, welcher Interpreter aufgerufen werden soll, und es muss ausführbar sein, um die "Berechtigung" zu haben, den Interpreter von seinem Shebang aus aufzurufen.

Wenn das Skript jedoch keinen Shebang hat, gibt es keine (direkten *) Informationen im Skript, die angeben, welcher Interpreter verwendet werden soll.

Nachdem ich das gesagt habe

Sie können natürlich jederzeit ein Wrapper-Skript schreiben, um herauszufinden, ob das Skript den Shebang enthält, und den Interpreter daraus lesen. Anschließend können Sie es über den gefundenen Interpreter ausführen.

Ein Beispiel

#!/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")
  • Speichern Sie es als tryrunin $PATH( ~/binmachen Sie das Verzeichnis, wenn es nicht existiert, melden Sie sich ab und wieder an), machen Sie es ausführbar . Dann läuft:

    tryrun /path/to/nonexecutablescript

    ruft (getestet) den richtigen Interpreter für meine nicht ausführbaren Dateien pythonund bashSkripte auf.

Erläuterung

  • Das Skript liest einfach die erste Zeile des Skripts, entfernt die #!und verwendet den Rest, um den Interpreter aufzurufen.
  • Wenn kein gültiger Interpreter aufgerufen wird, wird entweder a PermissionErroroder a ausgelöst FileNotFoundError.

Hinweis

Die Erweiterung ( .sh, .pyusw.) spielt überhaupt keine Rolle in dem entsprechenden Interpreter auf Linux zu bestimmen.


(* Es ist natürlich möglich, einen "intelligenten" Schätzalgorithmus zu entwickeln, um die Syntax aus dem Code zu bestimmen.)

Jacob Vlijm
quelle
OK, das bedeutet, dass Linux zwar irgendwo eine Shebang-Extraktion implementiert hat (damit es den richtigen Interpreter für ausführbare Skripte auswählen kann), jedoch nicht als eigenständiger Standardbefehl bereitgestellt wird.
Aivar
@Aivar, das den Schebang extrahiert, ist nicht das Problem, aber das Ausführen von Code ohne ihn ist durchaus möglich.
Jacob Vlijm
@Aivar Ah, ich verstehe, was du meinst. Wenn das Skript ausführbar ist und ohne Sprache im Befehl ausgeführt wird, ruft das Skript den Interpreter auf und nicht umgekehrt.
Jacob Vlijm
1
@JacobVlijm Ich würde nicht sagen, dass "das Skript den Interpreter aufruft", sondern eher, dass der Linux-Kernel die Shebang-Zeile verwendet, um herauszufinden, welcher Interpreter beim Ausführen des Skripts aufgerufen werden soll.
Paŭlo Ebermann,
@ PaŭloEbermann Danke! Stimmt natürlich. Der Kernel kümmert sich in beiden Fällen um die gesamte Prozedur, aber im übertragenen Sinne, und ich denke es ist besser zu verstehen, ist zu sagen, dass das Skript "erlaubt" ist, sich darum zu kümmern, welchen Interpreter es aufruft (und tatsächlich tut). Ich bin mir nicht sicher, was den Wortlaut betrifft, aber ich möchte ihn so beschreiben, als ob die Initiative im Skript enthalten wäre, während der Kernel tatsächlich die Arbeit erledigt.
Jacob Vlijm
6

Sie können dies mit einem Skript wie dem folgenden erreichen:

#!/bin/bash

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

Somit:

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

Ich empfehle dagegen. Berechtigungen gibt es aus einem Grund. Dies ist ein Programm zum Umkehren von Berechtigungen.

Beachten Sie, dass shebang handling eine Kernelfunktion ist (im Linux-Quellcode - fs/binfmt_script.c). Grundsätzlich weiß der Prozess, der ein Skript direkt aufruft, nichts über das #!- der Kernel verwendet es, um herauszufinden, dass er einen Interpreter starten muss.

schlank
quelle
2
Ich hatte immer angenommen, dass dies eine Funktion der Shell war, NICHT des Kernels. Heute etwas Neues gelernt.
Boatcoder
1
@boatcoder - Da Sie interessiert sind, haben Sie einen Link hinzugefügt, wo der Linux-Quellcode damit umgeht.
schlank