Ich habe Folgendes versucht, aber es scheint nicht zu funktionieren:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Ich habe Folgendes versucht, aber es scheint nicht zu funktionieren:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Antworten:
Der Grund, warum dies nicht funktioniert, liegt darin, dass es -i /bin/sh
als einziges Argument für env
. Normalerweise wären dies 2 Argumente -i
und /bin/sh
. Dies ist nur eine Einschränkung des Schebangs. Daran führt kein Weg vorbei.
Sie können diese Aufgabe jedoch auf eine andere Weise ausführen.
Wenn Sie möchten, dass diese Aufgabe vom Skript selbst ausgeführt wird und Sie nicht so etwas tun müssen env -i script.sh
, können Sie das Skript selbst erneut ausführen lassen.
#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
Dadurch wird das Skript von selbst erneut ausgeführt, wenn die CLEANED
Umgebungsvariable nicht festgelegt ist. Bei erneuter Ausführung setzt es die Variable, um sicherzustellen, dass sie nicht in eine Schleife gerät.
env
von den GNU-Coreutils haben nun die Option -S
, Probleme zu umgehen, die diesem ähnlich sind, aber nicht genau gleich sind. Zum Beispiel #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Achten Sie auf Portabilitätsprobleme.
Führen Sie Ihr Skript aus mit env -i
:
env -i script.sh
Und das Drehbuch wie gewohnt:
#!/bin/sh
# ... your code here
Wenn Sie mit einer sauberen Umgebung ausführen möchten, ohne dies beim Ausführen ausdrücklich zu erwähnen. Eduardo Ivanec gibt in dieser Antwort einige Ideen , mit denen Sie Ihr Skript rekursiv aufrufen können, exec
wenn die Umgebung nicht sauber ist (z. B. $ HOME ist definiert):
[ "$HOME" != "" ] && exec -c $0
Mit bash kannst du das so machen:
#!/usr/bin/bash
set -e
set -u
[ -v HOME ] && exec -c "$0" "$@"
# continue with the rest of the script
# e.g. print the cleaned environment:
export
Die Befehle set -e
und set -u
sind nicht unbedingt erforderlich, aber ich füge sie hinzu, um zu demonstrieren, dass dieser Ansatz nicht auf den Zugriff auf nicht gesetzte Variablen (wie z. B. [ "$HOME" != "" ]
) angewiesen ist und mit einer set -e
Einstellung kompatibel ist .
Das Testen der HOME
Variablen sollte sicher sein, da bash Skripte im nicht interaktiven Modus ausführt, dh Konfigurationsdateien wie ~/.bashrc
(wo Umgebungsvariablen gesetzt werden können) werden beim Start nicht bezogen.
Beispielausgabe:
declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
Die Linux-2-Argument-Shebang-Beschränkung (Interpeter + einzelnes Argument) ist in den meisten Antworten vermerkt, aber zu sagen, dass dies nicht möglich ist, ist falsch - Sie müssen nur zu einem Interpreter wechseln, der mit einem einzelnen Argument etwas Nützliches bewirken kann:
#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here
Dies geschieht perl
mit einem einzeiligen Skript ( -e
), das die Argumente löscht %ENV
(billiger als env -i
) und aufruft exec /bin/sh
, wobei die Argumente korrekt angegeben werden. perl
Bei Bedarf kann weitere Logik hinzugefügt werden (obwohl dies unter Linux nicht viel ist, da Sie sich auf BINPRM_BUF_SIZE
Zeichen beschränken , was wahrscheinlich 128 ist).
Leider ist dies Linux-spezifisch und funktioniert nicht auf einem System, das mehrere shebang-Argumente zulässt: - /
perl
Diese Zeichenfolge wird als einzelnes Argument verarbeitet. Sie wird daher nicht in Anführungszeichen gesetzt, wie dies normalerweise in perl -e ...
der Befehlszeile der Fall ist. Wenn Sie Anführungszeichen hinzufügen, werden diese beibehalten. Perl erkennt nur eine Literalzeichenfolge, die Warnungen enthält, und beschwert sich über eine unbrauchbare Zeichenfolge Konstante).
Beachten Sie auch, dass sich das Verhalten geringfügig ändert, wenn es auf diese Weise verwendet wird, @ARGV
normalerweise nur die Argumente $0
enthält und das Skript enthält. In diesem Fall $ARGV[0]
ist shebang der Name des Skripts (und $0
ist -e
), was es ein wenig einfacher macht.
Sie können dies auch mit einem Interpreter lösen, der seine Befehlszeile (ohne ein zusätzliches -c
Argument) "erneut verarbeitet", wie es das alte AT & T ksh93
tut:
#!/bin/ksh /usr/bin/env -i /bin/sh
obwohl das ksh
heutzutage vielleicht nicht mehr so ist ;-)
( bash
hat eine ähnliche Funktion mit --wordexp
, ist aber in den Versionen, in denen es funktioniert, "undokumentiert" und in den Versionen, in denen es dokumentiert ist, zur Kompilierungszeit nicht aktiviert: - / Es kann auch nicht dafür verwendet werden, da es zwei Argumente benötigt. ..)
Auch effektiv eine Variation der Antworten von @Patrick und @ maxschlepzig:
#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here
Anstatt Verwendung eine neue Variable Er nutzt die spezielle „ _
“ Variable, wenn es nicht gesetzt ist , genau zu „bash“ dann das Skript ersetzen exec
verwenden -a
zu machen ARGV[0]
(und damit $_
) nur „bash“, und mit -c
der Umwelt zu löschen.
Alternativ, wenn es akzeptabel ist, die Umgebung zu Beginn des Skripts zu bereinigen (nur Bash):
#!/bin/sh
unset $(compgen -e)
# your script here
Das verwendet compgen
(Completion Helper), um die Namen aller exportierten Umgebungsvariablen aufzulisten, und unset
s sie auf einmal.
Siehe auch Mehrere Argumente in shebang für weitere Details zum allgemeinen Problem des shebang-Verhaltens.