Do env lub nie do env


32

Jaka jest różnica między poleceniem

$ env FOO=bar baz

i

$ FOO=bar baz

Jaki efekt envma?


4
Coś w rodzaju pytania pobocznego, ale jak nazywa się ta funkcja, kiedy ustawiasz zmienną środowiskową dla jednej takiej komendy? Zawsze trudno mi było znaleźć informacje na ten temat, ponieważ nie wiem, jak się nazywa.
John Cromartie

1
@JohnCromartie, powinieneś zadać to pytanie.
cjm

1
Dla bash jest udokumentowane tutaj: gnu.org/software/bash/manual/…
glenn jackman

2
@JohnCromartie Jest to opcjonalny składnik każdego polecenia powłoki, dlatego znajduje się w sekcji „Proste polecenia” większości podręczników powłoki. W przypadku POSIX byłoby to tutaj . glenn połączył już dla ciebie analogiczną sekcję z podręcznika bash.
jw013

Ustawienie zmiennej, która nie istnieje za pomocą przypisania, tworzy zmienną powłoki. Ustawienie go za pomocą ENV lub wyeksportowanie zmiennej wypycha zmienną do środowiska wykonawczego powłoki. Zmiana wartości istniejącej zmiennej zaktualizuje wartość środowiska wykonawczego, jeśli taka istnieje, w przeciwnym razie zmień ją w wewnętrznych zmiennych powłoki.
Johan

Odpowiedzi:


26

Są funkcjonalnie równoważne.

Główna różnica polega na tym, że wywołuje się env FOO=bar bazproces pośredni między powłoką i baz, jak w FOO=bar bazprzypadku powłoki, bezpośrednio wywołuje baz.
W związku z tym FOO=bar bazjest preferowane.

Jedyne sytuacje, env FOO=barw których się przyzwyczajam, to przekazywanie polecenia innym poleceniom.
Jako konkretny przykład, powiedzmy, że mam skrypt otoki, który wykonuje pewne modyfikacje środowiska, a następnie wywołuje execprzekazane mu polecenie, takie jak:

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

Jeśli wykonasz to jako myscript FOO=bar baz, execwygeneruje błąd, ponieważ exec FOO=bar bazjest nieprawidłowy.
Zamiast tego wywołujesz go jako myscript env FOO=bar bazwykonywany jako exec env FOO=bar bazi jest on całkowicie poprawny.


1
Możesz to zrobić FOO=bar exec baz, więc nie potrzebujesz envostatniego punktu.
Stéphane Chazelas

Kiedy execcoś robisz , czy korzysta z twojego obecnego środowiska?
glenn jackman

1
Ditto @StephaneChazelas, a także sudo FOO=bar bazmożna przekazywać zmienne środowiskowe bez potrzeby env.
Mike Miller

1
@StephaneChazelas, który działa tylko wtedy, gdy chcę umieścić FOO=barw skrypcie. Jeśli FOOnie zawsze bar, nie chcę go kodować na sztywno, a zamiast tego przekazać.
Patrick

@glennjackman tak, tak długo, jak zmienne są eksportowane lub przekazywane przed exec, np FOO=bar exec baz.
Patrick

14

W tym konkretnym przykładzie nie ma skutecznej różnicy, zakładając, że twoja powłoka jest powłoką kompatybilną z POSIX, i zakładając, że bazjest wykonywalny, a nie wbudowany w powłokę.

Jeśli twoja powłoka nie jest powłoką kompatybilną z POSIX, na przykład cshlub tcshskładnia

FOO=bar baz

nie działa i nie ma równoważnej składni powłoki. W przypadku tych powłok envpolecenie jest jedynym sposobem na zastąpienie lub wstrzyknięcie zmiennych środowiskowych dla pojedynczego polecenia.

Jeśli bazjest wbudowana powłoka, powiedzmy fcna przykład, to envnie da takich samych wyników, ponieważ envwykonuje nowy proces zamiast być uruchamianym bezpośrednio przez powłokę poleceń. Co więcej, nie ma fcpliku wykonywalnego, można go uruchomić tylko jako wbudowaną powłokę ze względu na sposób, w jaki współdziała ona ze środowiskiem powłoki, a więc nigdy nieenv będzie działać z takim wbudowanym .fc

Ponadto envoferuje -iopcję, która pozwala uruchomić polecenie w pustym środowisku z określonym zestawem zmiennych środowiskowych. envMoże być więc bardzo przydatny na przykład do uruchamiania procesów w środowiskach odkażonych

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz

Kiedyś używałem tcsh, pisałem, (setenv FOO bar; baz)aby uzyskać równoważną funkcję.
Barmar

6

Oprócz tego, co już zostało powiedziane

VAR=value cmd args > redirs

będąc funkcją powłoki (Bourne / POSIX), masz ograniczoną nazwę zmiennych środowiskowych, które przekazujesz cmd. Muszą być poprawnymi nazwami zmiennych powłoki i nie mogą być zmiennymi tylko do odczytu lub specjalnymi zmiennymi dla powłoki.

Na przykład nie można wykonać:

1=foo cmd

Lub

+++=bar cmd

bash nie pozwala ci na:

SHELLOPTS=xtrace cmd

Chociaż możesz to zrobić:

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

(nie że chcesz lub powinieneś to zrobić). Lub:

env SHELLOPTS=xtrace cmd

(Czasami muszę to zrobić).

Zauważ, envże nadal nie możesz przekazać łańcucha zmiennej środowiskowej, który nie zawiera =(nie, że też chciałbyś to zrobić).


2

Jednym z zastosowań envjest umożliwienie $PATHwyszukiwania plików wykonywalnych w liniach shebang (ponieważ bierze envpod uwagę $PATHprzy wyszukiwaniu plików wykonywalnych). Jest to przydatne, jeśli plik wykonywalny, który chcesz wywołać, może znajdować się w różnych miejscach na różnych komputerach. Na przykład,

#!/usr/bin/env perl

w pierwszym wierszu skryptu z zestawem bitów wykonywalnych uruchomi ten skrypt w Perlu bez względu na to, czy jest on zainstalowany /usr/bin/perlw/usr/local/bin/perl innym miejscu, o ile katalog znajduje się na ścieżce.

Oczywiście, wyszukiwanie ścieżki wiąże się z dodatkowym ryzykiem, ale ryzyko to nie jest większe niż w przypadku wyraźnego napisania perl yourscript.pl, co również wyszukuje perla na ścieżce wyszukiwania.


2

Innym razem, gdy envjest to naprawdę przydatne, jest to, że chcesz całkowicie kontrolować środowisko. Uruchamiam program serwera (Informix, na wypadek, gdybyś nie zgadł), którego środowiskiem chcę całkowicie kontrolować. Uruchamiam go za envpomocą skryptu, który ustawia kilka zmiennych do poprawnych wartości:

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 "$@"

Ta -iopcja zapełnia istniejące środowisko. Kolejne VAR=valueopcje ustawiają zmienne środowiskowe, które chcę ustawić; nazwa programu jest w $ONINIT, a wszelkie argumenty wiersza poleceń są przekazywane dosłownie za pomocą "$@".

${IXH:+INFORMIXSQLHOSTS="$IXH"}Konstrukt przechodzi tylko INFORMIXSQLHOSTS="$IXH"do envJeśli $IXHustawiony jest niepusty wartości.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.