Odznacz zmienną środowiskową dla jednego polecenia


24

Mogę ENV_VAR=value commandbiegać commandz określoną wartością dla ENV_VAR. Co to jest równoważne rozbroić ENV_VARza command?


7
Poza tym: commandjest niefortunnym wyborem symboli zastępczych, ponieważ tak naprawdę istnieje wbudowane polecenie o tej nazwie. mycommandlub somecommandcoś takiego może być lepszym nawykiem do wejścia.
Charles Duffy

@CharlesDuffy, zwykle używam cmddo tego.
Stéphane Chazelas

Odpowiedzi:


35

Poza -iopcją, która usuwa całe środowisko, POSIX envnie zapewnia żadnego sposobu na rozbrojenie zmiennej.

Jednak za pomocą kilku envimplementacji (w tym busyboxco najmniej GNU, 'i FreeBSD) możesz:

env -u ENV_VAR command

Który działałby przy usuwaniu każdego wystąpienia ENV_VARzmiennej ze środowiska (zauważ jednak, że nie działa on dla zmiennej środowiskowej o pustej nazwie ( env -u ''albo daje błąd, albo jest nieskuteczny w zależności od implementacji, mimo że wszystkie akceptują env '=value', prawdopodobnie ograniczenie) ponoszone przez funkcję unsetenv()C, która POSIX wymaga zwrócenia błędu pustego łańcucha, podczas gdy nie ma takiego ograniczenia putenv())).

Przenośnie (w powłokach POSIX) możesz:

(unset -v ENV_VAR; exec command)

(zwróć uwagę, że w przypadku niektórych powłok użycie polecenia execcan change, które commandjest uruchomione: uruchamia ten w systemie plików zamiast funkcji lub na przykład wbudowanego (i aliasoczywiście envpomija rozszerzenie), jak wyżej. W takich przypadkach należy go pominąć) .

Ale to nie zadziała w przypadku zmiennych środowiskowych, których nazwy nie da się zmapować na zmienną powłoki (zwróć uwagę, że niektóre takie powłoki i tak usuwają mkshte zmienne ze środowiska podczas uruchamiania), lub zmienne oznaczone jako tylko do odczytu.

-vjest dla powłoki Bourne'a i bez bashktórej mogłaby rozbroić funkcję, gdyby nie było zmiennej o tej nazwie. Większość innych powłok nie rozbroiłaby funkcji, chyba że podasz opcję. (mało prawdopodobne, aby zmieniło się w praktyce).unset-vENV_VAR -f

(Uważaj również na błąd / błędne działanie bash/ mksh/ yashktórego unsetw pewnych okolicznościach może nie rozbroić zmiennej, ale ujawnić zmienną w zakresie zewnętrznym )

Jeśli perljest dostępny, możesz:

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

Który będzie działał nawet dla zmiennej środowiskowej o pustej nazwie.

Teraz wszystkie te nie będą działać, jeśli chcesz zmienić zmienną środowiskową dla wbudowanej funkcji lub funkcji i nie chcesz, aby działały w podpowłoce, np . 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

(tutaj rozbrajanie LANG jako błędne podejście do upewnienia się, że .jest używane i rozumiane jako separator dziesiętny. Lepiej byłoby użyć LC_ALL=C printf...do tego)

W przypadku niektórych powłok można zamiast tego utworzyć zasięg lokalny dla zmiennej za pomocą funkcji:

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

Za pomocą zshmożesz także użyć anonimowej funkcji:

(){local ENV_VAR; command}

Takie podejście nie będzie działać w niektórych powłokach (takich jak te oparte na powłoce Almquist), localktóre nie deklarują zmiennej jako początkowo nieuzbrojonej (ale dziedziczą wartość i atrybuty). W tych przypadkach możesz to zrobić local ENV_VAR; unset ENV_VAR, ale nie rób tego w mkshlub yash( typesetzamiast localtego), ponieważ to nie zadziała, unsetbyłoby tylko anulowanie local.

¹ Strzeż się również, że w bashtym przypadku lokalny ENV_VAR(nawet jeśli nie jest ustawiony) zachowałby atrybut eksportu . Gdyby więc commandbyła funkcja, która przypisuje wartość ENV_VAR, zmienna byłaby dostępna w środowisku poleceń wywoływanych później. unset ENV_VARwyczyści ten atrybut. Lub możesz użyć tego, local +x ENV_VARco zapewniłoby również czyste konto (chyba że zmienna została zadeklarowana jako tylko do odczytu, ale wtedy nic nie możesz na to poradzić bash).


1
To osobne pytanie, ale co do cholery jest zmienną środowiskową o pustej nazwie i jak byś jej używał - nawet do pewnego rodzaju exploita? Czy nie musiałbyś pisać programu, który odczytuje środowisko i szuka czegoś takiego?
Joe

@Joe, spróbuj na przykład env '=foo' python -c 'import os; print os.environ[""]'. Nie oczekuję, że wiele osób chciałoby ustawić taką zmienną.
Stéphane Chazelas,

9

O ile mi wiadomo, nie ma bezpośredniego odpowiednika; możesz użyć podpowłoki:

(unset ENV_VAR; exec command)

(unset ENV_VAR; exec somecommand)jeśli chcesz być równoważny z oryginałem pod względem wydajności (poprzez konsumpcję podpowłoki). W tej chwili dodaje to dodatkowy widelec.
Charles Duffy,

1
@Charles rzeczywiście, chociaż niektóre powłoki robią to automatycznie, ponieważ commandjest to ostatnie polecenie w wywołaniu podpowłoki.
Stephen Kitt

+1, ponieważ w ten sposób można łatwo wpisać do użytku interaktywnego. Używam podpowłoki do jednorazowych zmian w środowisku powłoki dla jednowarstwowego zamiast pamiętać, że tak jest env -u.
Peter Cordes,

0

Możesz użyć ENV_VAR= command

W rzeczywistości nie powoduje to rozbrojenia zmiennej, ale może być przydatne w wielu przypadkach (skrypty powłoki zwykle służą test -ndo sprawdzenia, czy zmienna jest ustawiona):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
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.