Deaktivieren Sie eine Umgebungsvariable für einen Befehl

24

Ich kann laufen ENV_VAR=value command, um commandmit einem bestimmten Wert für zu laufen ENV_VAR. Was ist das Äquivalent zu unset ENV_VARfür command?

Alexey Romanov
quelle
7
Abgesehen: commandist eine unglückliche Wahl der Platzhalter, da es tatsächlich ist ein integrierter Befehl mit diesem Namen. mycommandoder somecommandoder so könnte eine bessere Angewohnheit sein, um
Charles Duffy
@CharlesDuffy, ich benutze normalerweise cmddafür.
Stéphane Chazelas

Antworten:

35

Anders als mit der -iOption, die die gesamte Umgebung löscht, envbietet POSIX keine Möglichkeit, eine Variable zu löschen.

Mit ein paar envImplementierungen (einschließlich GNUs busyboxund FreeBSDs) können Sie jedoch Folgendes tun:

env -u ENV_VAR command

Dies würde dazu führen, dass jede Instanz einer ENV_VARVariablen aus der Umgebung entfernt wird (beachten Sie jedoch, dass dies für die Umgebungsvariable mit leerem Namen nicht funktioniert). env -u ''Dies führt je nach Implementierung entweder zu einem Fehler oder ist unwirksam, auch wenn alle dies akzeptieren env '=value', wahrscheinlich eine Einschränkung entsteht durch die unsetenv()C-Funktion, die POSIX benötigt, um einen Fehler für den leeren String zurückzugeben, während es für putenv())) keine solche Einschränkung gibt .

Portabel (in POSIX-Shells) können Sie:

(unset -v ENV_VAR; exec command)

(Beachten Sie, dass bei einigen Shells die Verwendung execändern kann, was ausgeführt commandwird: führt die im Dateisystem statt einer Funktion oder zum Beispiel einer eingebauten aus (und würde die aliasErweiterung offensichtlich umgehen ), wie envoben. Sie möchten es in diesen Fällen weglassen.) .

Dies funktioniert jedoch nicht für Umgebungsvariablen mit einem Namen, der keiner Shell-Variablen zugeordnet werden kann (beachten Sie, dass einige Shells mkshdiese Variablen ohnehin beim Start aus der Umgebung entfernen würden), oder für Variablen, die als schreibgeschützt markiert wurden.

-vist für die Bourne-Shell und bashderen unsetwithout -vkönnte eine ENV_VAR Funktion deaktivieren , wenn es keine Variable mit diesem Namen gäbe . Die meisten anderen Shells würden Funktionen nur dann deaktivieren, wenn Sie die -fOption übergeben. (Es ist unwahrscheinlich, dass dies in der Praxis einen Unterschied macht.)

(Auch passen sie vom Bug / misfeature von bash/ mksh/ yashdessen unsetunter gewissen Umständen nicht die Variable unset kann, aber offenbaren die Variable in einem äußeren Umfang )

Wenn perlverfügbar, können Sie Folgendes tun:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

Was auch für die Umgebungsvariable mit einem leeren Namen funktionieren wird.

Jetzt funktionieren all diese Funktionen nicht mehr, wenn Sie eine Umgebungsvariable für eine integrierte Funktion oder Funktion ändern und nicht möchten, dass sie in einer Subshell ausgeführt werden, wie in bash:

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(Hier wird LANG als falsch eingestellter Ansatz verwendet, um sicherzustellen, dass .das Dezimaltrennzeichen verwendet und verstanden wird. Es ist besser, dies zu tun . LC_ALL=C printf...)

Bei einigen Shells können Sie stattdessen einen lokalen Bereich für die Variable mithilfe einer Funktion erstellen:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

Mit zshkönnen Sie auch eine anonyme Funktion verwenden:

(){local ENV_VAR; command}

Dieser Ansatz funktioniert nicht in einigen Shells (wie denjenigen, die auf der Almquist-Shell basieren), deren localVariable nicht als anfänglich nicht festgelegt deklariert wird (sondern deren Wert und Attribute erbt). In denen kannst du das machen local ENV_VAR; unset ENV_VAR, aber mach das nicht in mkshoder yash( typesetanstatt localfür das eine), da das nicht funktionieren würde, das unsetwürde nur das abbrechen local.

¹ Sie auch , dass in passen bash, die lokal ENV_VAR(auch wenn ungesetzt) würden das behalten Export - Attribut. Wenn commandes sich also um eine Funktion handelt, die einen Wert zuweist ENV_VAR, ist die Variable in der Umgebung der anschließend aufgerufenen Befehle verfügbar. unset ENV_VARwürde dieses Attribut löschen. Oder Sie könnten verwenden, local +x ENV_VARwas ebenfalls für einen sauberen Slate sorgen würde (es sei denn, diese Variable wurde als schreibgeschützt deklariert, aber Sie können nichts dagegen tun bash).

Stéphane Chazelas
quelle
1
Es ist eine separate Frage, aber was zum Teufel ist eine Umgebungsvariable mit einem leeren Namen und wie würden Sie sie jemals verwenden - auch für eine Art Exploit? Müssten Sie nicht ein Programm schreiben, das die Umgebung liest und speziell nach so etwas sucht?
Joe
@ Joe, versuchen Sie es zum Beispiel env '=foo' python -c 'import os; print os.environ[""]'. Ich erwarte nicht, dass viele Leute so eine Variable setzen wollen.
Stéphane Chazelas
9

Soweit ich weiß, gibt es keine direkte Entsprechung. Sie können eine Unterschale verwenden:

(unset ENV_VAR; exec command)
Stephen Kitt
quelle
(unset ENV_VAR; exec somecommand)wenn Sie in der Effizienz dem Original entsprechen möchten (indem Sie die Unterschale verbrauchen). So wie es ist, fügt dies eine zusätzliche Gabel hinzu.
Charles Duffy
1
@Charles in der Tat, obwohl einige Shells dies automatisch tun, da dies commandder letzte Befehl im Subshell-Aufruf ist.
Stephen Kitt
+1, da diese Methode für die interaktive Verwendung einfach einzugeben ist. Ich verwende Subshells für einmalige Änderungen an der Shell-Umgebung für einen Einzeiler, anstatt mich daran zu erinnern, dass dies der Fall ist env -u.
Peter Cordes
0

Sie können verwenden ENV_VAR= command

Dadurch wird die Variable nicht wirklich deaktiviert, aber es kann in vielen Fällen nützlich sein (Shell-Skripte werden normalerweise nur verwendet) test -n , um zu überprüfen, ob eine Variable festgelegt ist):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
GnP
quelle