Wie starte ich ein Skript mit einer sauberen Umgebung?

15

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.
balki
quelle
Gefundene ähnliche Fragen, zeigt aber nicht, wie es mit shebang
geht
5
Sie können es nicht von Shebang tun. Der Shebang kann nur ein Argument akzeptieren.
Jordan

Antworten:

7

Der Grund, warum dies nicht funktioniert, liegt darin, dass es -i /bin/shals einziges Argument für env. Normalerweise wären dies 2 Argumente -iund /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 CLEANEDUmgebungsvariable nicht festgelegt ist. Bei erneuter Ausführung setzt es die Variable, um sicherzustellen, dass sie nicht in eine Schleife gerät.

Patrick
quelle
envvon 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.
Weijun Zhou
Gerade versucht. Es funktioniert auch für die ursprüngliche Frage. Verwenden Sie einfach #!/usr/bin/env -S -i /bin/sh. Achten Sie auf Portabilitätsprobleme.
Weijun Zhou
3

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, execwenn die Umgebung nicht sauber ist (z. B. $ HOME ist definiert):

[ "$HOME" != "" ] && exec -c $0
RSFalcon7
quelle
Nett. Tun Sie einfach nicht env -i bash wie ich und fragen Sie sich dann, warum Ihre env-Variablen noch gesetzt sind (natürlich bash-Ressourcen .bashrc und Freunde 8)
Neil McGill
2

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 -eund set -usind 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 -eEinstellung kompatibel ist .

Das Testen der HOMEVariablen 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"
maxschlepzig
quelle
0

$ cat script.sh

#!/bin/env -i /bin/sh

Leider funktioniert das nicht so - Linux ist -i /bin/shein Argument, an das weitergegeben werden muss env(siehe Shebang ).

Poige
quelle
0

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 perlmit 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. perlBei Bedarf kann weitere Logik hinzugefügt werden (obwohl dies unter Linux nicht viel ist, da Sie sich auf BINPRM_BUF_SIZEZeichen beschränken , was wahrscheinlich 128 ist).

Leider ist dies Linux-spezifisch und funktioniert nicht auf einem System, das mehrere shebang-Argumente zulässt: - /

perlDiese 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, @ARGVnormalerweise nur die Argumente $0enthält und das Skript enthält. In diesem Fall $ARGV[0]ist shebang der Name des Skripts (und $0ist -e), was es ein wenig einfacher macht.

Sie können dies auch mit einem Interpreter lösen, der seine Befehlszeile (ohne ein zusätzliches -cArgument) "erneut verarbeitet", wie es das alte AT & T ksh93tut:

#!/bin/ksh /usr/bin/env -i /bin/sh

obwohl das kshheutzutage vielleicht nicht mehr so ​​ist ;-)

( bashhat 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 execverwenden -azu machen ARGV[0](und damit $_) nur „bash“, und mit -cder 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 unsets sie auf einmal.

Siehe auch Mehrere Argumente in shebang für weitere Details zum allgemeinen Problem des shebang-Verhaltens.

mr.spuratic
quelle