Um zu beneiden oder nicht

32

Was ist der Unterschied zwischen dem Befehl

$ env FOO=bar baz

und

$ FOO=bar baz

Welchen Effekt hat envdas?

August Karlstrom
quelle
4
Eine Art Nebenfrage, aber wie heißt das Feature selbst, wenn Sie eine Umgebungsvariable für einen einzelnen Unterbefehl wie diesen festlegen? Es fiel mir immer schwer, Informationen darüber zu finden, weil ich nicht weiß, wie sie heißen.
John Cromartie
1
@ JohnCromartie, das solltest du als Frage stellen.
cjm
1
Für Bash ist es hier dokumentiert: gnu.org/software/bash/manual/…
Glenn Jackman
2
@JohnCromartie Dies ist eine optionale Komponente jedes Shell-Befehls. Sie befindet sich daher in den meisten Shell-Handbüchern im Abschnitt "Einfache Befehle". Für POSIX wäre das hier . glenn hat den analogen abschnitt aus dem bash-handbuch schon für dich verlinkt.
jw013
Wenn Sie eine Variable festlegen, die nicht über eine Zuweisung vorhanden ist, wird eine Shell-Variable erstellt. Durch das Festlegen über ENV oder das Exportieren der Variablen wird die Variable in die Ausführungsumgebung der Shell verschoben. Wenn Sie den Wert einer vorhandenen Variablen ändern, wird der Wert der Ausführungsumgebung aktualisiert, sofern vorhanden. Andernfalls ändern Sie ihn in den internen Shell-Variablen.
Johan

Antworten:

26

Sie sind funktional gleichwertig.

Der Hauptunterschied besteht darin, dass env FOO=bar bazein zwischengeschalteter Prozess zwischen der Shell und aufgerufen wird baz, der wie bei FOO=bar bazder Shell direkt aufgerufen wird baz.
Also in dieser Hinsicht FOO=bar bazbevorzugt.

Die einzigen Situationen, env FOO=barin denen ich mich befinde, sind Situationen, in denen ich einen Befehl an einen anderen Befehl übergeben muss.
Nehmen wir als konkretes Beispiel an, ich habe ein Wrapper-Skript, das einige Änderungen an der Umgebung vornimmt und dann execden Befehl aufruft, der an das Skript übergeben wurde, wie zum Beispiel:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

Wenn Sie es ausführen myscript FOO=bar baz, execwird ein exec FOO=bar bazungültiger Fehler ausgegeben.
Stattdessen nennst du es als myscript env FOO=bar bazwas ausgeführt wird als exec env FOO=bar bazund ist vollkommen gültig.

Patrick
quelle
1
Das kannst du FOO=bar exec bazaber, also brauchst du envin deinem letzten Punkt nicht.
Stéphane Chazelas
Wenn Sie execetwas tun, nutzt es Ihre aktuelle Umgebung?
Glenn Jackman
1
Das Gleiche gilt für @StephaneChazelas, und Sie können auch sudo FOO=bar bazUmgebungsvariablen übergeben, ohne dass dies erforderlich ist env.
Mike Miller
1
@StephaneChazelas, das funktioniert nur, wenn ich FOO=bardas Skript einfügen möchte . Wenn dies FOOnicht immer der barFall ist, möchte ich es nicht hart codieren und stattdessen weitergeben.
Patrick,
@glennjackman tut es ja, solange die Variablen exportiert oder vor dem übergeben werden exec, wie z FOO=bar exec baz.
Patrick
14

In diesem speziellen Beispiel gibt es keinen effektiven Unterschied, vorausgesetzt, Ihre Shell ist eine POSIX-kompatible Shell, und vorausgesetzt, es bazhandelt sich um eine ausführbare Datei und nicht um eine eingebaute Shell.

Wenn Ihre Shell beispielsweise keine POSIX-kompatible Shell ist cshodertcsh die Syntax

FOO=bar baz

funktioniert nicht und es gibt keine äquivalente Shell-Syntax. Für diese Shells ist der envBefehl die einzige Möglichkeit, Umgebungsvariablen für einen einzelnen Befehl zu überschreiben oder einzufügen.

Wenn bazeine Shell - builtin ist, sagen sie fczum Beispiel dann envnicht die gleichen Ergebnisse liefern, weil envein neues Verfahren ausgeführt wird, anstatt dass sie direkt von dem Kommando - Shell ausgeführt werden . Darüber hinaus gibt es keine fcausführbare Datei, kann es nur als Shell - builtin ausgeführt werden , da der Weg , um es mit dem Shell - Umgebung interagiert, und so envwird nie Arbeit mit einem builtin wiefc .

Darüber hinaus envbietet die -iOption, die Sie einen Befehl in einer leeren Umgebung mit nur einer bestimmten Gruppe von Umgebungsvariablen starten kann. Dies envkann beispielsweise beim Starten von Prozessen in hygienisierten Umgebungen sehr nützlich sein

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz
Mike Miller
quelle
Wenn ich verwendet tcshhabe, würde ich schreiben (setenv FOO bar; baz), um die entsprechende Funktion zu erhalten.
Barmar
6

Zusätzlich zu dem, was bereits gesagt wurde

VAR=value cmd args > redirs

Da es sich um eine Shell-Funktion (Bourne / POSIX) handelt, ist der Name der Umgebungsvariablen, an die Sie übergeben, beschränkt cmd. Sie müssen gültige Shell-Variablennamen sein und dürfen keine schreibgeschützten oder speziellen Variablen für die Shell sein.

Zum Beispiel können Sie nicht tun:

1=foo cmd

Oder

+++=bar cmd

bash erlaubt dir nicht:

SHELLOPTS=xtrace cmd

Während Sie tun können:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(nicht, dass Sie das wollen oder wollen sollten). Oder:

env SHELLOPTS=xtrace cmd

(Ich muss das manchmal tun).

Beachten Sie, dass envSie immer noch keine Umgebungsvariablenzeichenfolge übergeben können, die kein a enthält =(nicht, dass Sie das auch tun möchten).

Stéphane Chazelas
quelle
2

Eine Verwendung von envist, die $PATHSuche nach ausführbaren Dateien in Shebang-Zeilen zuzulassen (da dies bei der Suche nach der ausführbaren Datei envberücksichtigt wird $PATH). Dies ist nützlich, wenn sich die ausführbare Datei, die Sie aufrufen möchten, möglicherweise an verschiedenen Stellen auf verschiedenen Computern befindet. Beispielsweise,

#!/usr/bin/env perl

in der ersten Zeile eines Skripts mit ausführbaren Bit gesetzt wird dieses Skript mit Perl ausführen , egal , ob es installiert ist /usr/bin/perloder in /usr/local/bin/perloder in einem ganz anderen Ort, solange das Verzeichnis in dem Pfad.

Natürlich bringt diese Pfadsuche ein zusätzliches Risiko mit sich, aber dann ist das Risiko nicht größer, als wenn Sie es explizit geschrieben hätten perl yourscript.pl, wodurch auch Perl im Suchpfad nachgeschlagen wird.

Celtschk
quelle
2

Ein anderes Mal, wenn enves wirklich nützlich ist, möchten Sie die Umgebung vollständig steuern. Ich führe ein Serverprogramm aus (Informix, falls Sie es nicht erraten können), dessen Umgebung ich vollständig steuern möchte. Ich führe es envam Ende eines Skripts aus, das eine Reihe von Variablen auf die richtigen Werte setzt:

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

Die -iOption zappt die vorhandene Umgebung. Die nachfolgenden VAR=valueOptionen legen die Umgebungsvariablen fest, die ich festlegen möchte. Der Name des Programms ist in $ONINITund alle Befehlszeilenargumente werden wörtlich mit übergeben "$@".

Das ${IXH:+INFORMIXSQLHOSTS="$IXH"}Konstrukt wird nur übergeben INFORMIXSQLHOSTS="$IXH", envwenn $IXHein nicht leerer Wert festgelegt ist.

Jonathan Leffler
quelle