Kann ich einen variablen Inhalt als Shebang verwenden?

Kann ich einen variablen Inhalt als Shebang verwenden?

Ich habe ein Shell-Skript, in das ich ein Shebang einfügen möchte. Gegeben sei eine Variable, die wie folgt definiert ist:

SHEBANG="#!/bin/sh"

Meine Frage ist, ob ich diese Variable in einem anderen Skript wie diesem verwenden kann:

$SHEBANG
# other stuff...

Antwort1

Nein. Die Shebang-Zeile wird von Ihrem Kernel oder Ihrer Systembibliothek* verarbeitet und verarbeitet keine Shell-Variablen.

  • Wenn Sie aus irgendeinem Grund eine Umgebungsvariable als Interpreter verwenden möchten, können Sie eine ausführbare „Trampolin“-Datei (kein Skript!) erstellen, die erneut startet $SHEBANG "$@". In diesem Fall müssen Sie das #!aus der Variable weglassen; #!ist nur nützlich, wenn es sich buchstäblich um die ersten beiden Bytes einer Datei handelt.

  • Eine weitere Möglichkeit ist die Nutzung vonshdie Tatsache, dass Skripte ohne Shebang-Zeilen (im Allgemeinen) als Shell-Skripte entweder mit oder mit der aufrufenden Shell ausgeführt werden. Wenn es eine Kommentarsyntax für Ihr Shebang-Ziel gibt, die sich sinnvoll mit der Shell-Syntax überschneidet, könnten Sie es zum Laufen bringen. Diese Strategie ist oder war bei Lisp-Interpretern üblich. In Ihrem Beispiel, wo der Interpreter auch ist sh, ist dies nicht praktikabel.

  • Sie können die Dinge auf dieser Zeile noch weiter vorantreiben, wenn Sie sich darauf verlassen können, bashdass sie präsent sind: ein Skript, dessen erste Zeile lautet

    exec /bin/bash -c 'exec "$SHEBANG" <(tail -n +2 "$0")' "$0" "$@"
    

    funktioniert für die meisten Interpreter; Bash wird als Zwischenschritt verwendet, so dassProzesssubstitutionkann verwendet werden, umtailüberspringe die erste Zeile für uns, damit wir nicht in einer Endlosschleife landen. Einige Interpreter erfordern, dass die Datei durchsuchbar ist, und sie akzeptieren eine solche Pipeline nicht.


Es lohnt sich, darüber nachzudenken, ob Sie das wirklich tun möchten. Abgesehen von Sicherheitsbedenken ist es einfach nicht sehr nützlich: Bei wenigen Skripten kann man den Interpreter auf diese Weise austauschen, und wo dies möglich ist, wäre man mit Sicherheit mit einer eingeschränkteren Logik besser dran, die die richtige Logik für die jeweilige Situation erzeugt (vielleicht ein Shell-Skript dazwischen, das den Interpreter mit dem Pfad zum echten Skript als Argument aufruft).


* Nicht immer; unter bestimmten Umständen lesen einige Shells es selbst, führen aber trotzdem keine Variablenerweiterung durch.

Antwort2

Ich weiß nicht, ob das der Anwendungsfall ist, den Sie im Sinn haben, aber einesdürfentun ist

#!/usr/bin/env python

Ihr Skript verwendet also das erste pythonin, $PATHanstatt es fest codieren zu müssen /usr/bin/python, was auf manchen Systemen, auf denen die „gute“ Python-Version in /usr/local/binoder /optwas auch immer vorhanden ist, möglicherweise nicht gut funktioniert.

Warum ist es besser, „#!/usr/bin/env NAME“ statt „#!/path/to/NAME“ als meinen Shebang zu verwenden?


Dies erzeugt keine Endlosschleife, da der Python-Interpreter (der envdie Datei aufruft) die #!Zeile einfach als Kommentar behandelt. Dies ist sozusagen der Sinn des #!Entwurfs, da viele Sprachen #als Kommentarzeichen verwenden.

Um dies zu erweitern,Sie könnten ein polyglottes Programm schreibendas zunächst unter ausgeführt wird #!/bin/sh, dann aber herausfindet, welcher Interpreter tatsächlich verwendet werden soll, und diesen im selben Skript aufruft.

Es stellt sich heraus, dass es bereitseine Webseite mit mehrzeiligen Shebang-Tricksfür viele Sprachen, einschließlich kompilierter Sprachen (das Skript gibt einen Teil von sich selbst an einen Compiler weiter und führt die Ausgabe aus).


Die perlrunManpage bietet dieses Beispiel als Alternative zu #!/usr/bin/env perl:

    #!/bin/sh
    #! -*-perl-*-
    eval 'exec perl -x -wS $0 ${1+"$@"}'
        if 0;

    your perl script goes here

Wenn es als /bin/shSkript ausgeführt wird, wird es auf Ihrem Skript evalausgeführt perl -x -wSund übergibt Ihre Argumente.

Wenn Perl es ausführt, wird es durch das in der nächsten Zeile evalgesteuert , sodass es nie ausgeführt wird. Im Gegensatz zu werden Perl-Anweisungen nicht durch eine neue Zeile beendet.if 0;sh

Sie können dies noch komplexer gestalten, indem Sie "$SHEBANG"anstelle von verwenden perloder sogar mehrere shBefehle ausführen, um einen zu verwendenden Perl-Interpreter auszuwählen.

Antwort3

Ich denke, das ist, was Sie wollen:

xb@dnxb:/tmp$ cat /tmp/hole.sh
#!/usr/bin/$shell_var
echo 1
readlink "/proc/$$/exe"
echo 2
function f { echo hello world; } 
echo 3 
xb@dnxb:/tmp$ chmod +x /tmp/hole.sh
xb@dnxb:/tmp$ sudo vi /usr/bin/\$shell_var 
xb@dnxb:/tmp$ cat /usr/bin/\$shell_var 
#!/bin/bash
/bin/dash -- "$@"
xb@dnxb:/tmp$ sudo chmod +x /usr/bin/\$shell_var
xb@dnxb:/tmp$ ./hole.sh
1
/bin/dash
2
./hole.sh: 5: ./hole.sh: function: not found
3
xb@dnxb:/tmp$ sudo vi /usr/bin/\$shell_var 
xb@dnxb:/tmp$ cat /usr/bin/\$shell_var 
#!/bin/bash
/bin/bash -- "$@"
xb@dnxb:/tmp$ ./hole.sh 
1
/bin/bash
2
3
xb@dnxb:/tmp$ 

Erläuterung:

  1. Verwenden Sie \$shell_vardie Datei „act“ als „Variable“, um die gewünschte Shell zu definieren.

  2. readlink "/proc/$$/exe"druckt die aktuelle Shell.

  3. Da Dash nicht unterstütztfunction f { echo hello world; }Syntax, daher trat ein Fehler auf function: not found, aber durch Ändern der Shell in \$shell_varder Datei zu Bash tritt kein Fehler mehr auf.

  4. Der vollständige Dateipfad (oder der relative Pfad, wenn ./hole.sh in /tmp ausgeführt wird) wird als Datei übergeben $@und \$shell_vardarin /tmp/hole.shausgeführt \$shell_var.

verwandte Informationen