Disattiva una variabile di ambiente per un comando


24

Posso correre ENV_VAR=value commandper funzionare commandcon un valore specifico per ENV_VAR. Qual è l'equivalente di unset ENV_VARper command?


7
A parte: commandè una scelta sfortunata di segnaposto, poiché in realtà esiste un comando integrato con quel nome. mycommando somecommando potrebbe essere un'abitudine migliore per entrare.
Charles Duffy,

@CharlesDuffy, di solito lo uso cmdper quello.
Stéphane Chazelas,

Risposte:


35

A parte l' -iopzione, che cancella l'intero ambiente, POSIX envnon fornisce alcun modo per disinserire una variabile.

Tuttavia, con alcune envimplementazioni (inclusi GNU, busybox'e almeno FreeBSD), puoi fare:

env -u ENV_VAR command

Che funzionerebbe nel rimuovere ogni istanza di una ENV_VARvariabile dall'ambiente (nota però che non funziona per la variabile d'ambiente con un nome vuoto ( env -u ''o dà un errore o è inefficace a seconda dell'implementazione anche se tutti accettano env '=value', probabilmente una limitazione sostenuto dalla unsetenv()funzione C che POSIX richiede per restituire un errore per la stringa vuota, mentre non esiste tale limitazione per putenv())).

Portabilmente (nelle shell POSIX), puoi fare:

(unset -v ENV_VAR; exec command)

(nota che con alcune shell, usare execpuò cambiare ciò che commandviene eseguito: esegue quello nel filesystem invece di una funzione o builtin per esempio (e aliasovviamente ignorerebbe l' espansione), come envsopra. In questi casi vorrai ometterlo) .

Ma ciò non funzionerà per le variabili di ambiente che hanno un nome che non è mappabile a una variabile di shell (si noti che alcune shell come mkshrimuoveranno comunque quelle variabili dall'ambiente all'avvio), o variabili che sono state contrassegnate come di sola lettura.

-vè per la shell Bourne e il bashcui unsetsenza -vpotrebbe annullare l'impostazione di una ENV_VAR funzione se non vi fosse alcuna variabile con quel nome. La maggior parte delle altre shell non disinserire le funzioni se non si passa l' -fopzione. (è improbabile che faccia la differenza nella pratica).

(Fai attenzione anche al bug / al malfunzionamento di bash/ mksh/ il yashcui unset, in alcune circostanze, potrebbe non disinserire la variabile, ma rivelare la variabile in un ambito esterno )

Se perlè disponibile, puoi fare:

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

Che funzionerà anche per la variabile d'ambiente con un nome vuoto.

Ora tutti quelli non funzioneranno se si desidera modificare una variabile di ambiente per un builtin o una funzione e non si desidera che vengano eseguiti in una subshell, come 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

(qui disinserendo LANG come approccio errato per assicurarsi che .sia usato e inteso come separatore decimale. Sarebbe meglio usarlo LC_ALL=C printf...per quello)

Con alcune shell, puoi invece creare un ambito locale per la variabile usando una funzione:

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

Con zsh, puoi anche usare una funzione anonima:

(){local ENV_VAR; command}

Questo approccio non funzionerà in alcune shell (come quelle basate sulla shell Almquist), le quali localnon dichiarano la variabile inizialmente non impostata (ma ereditano il valore e gli attributi). In quelli, puoi farlo local ENV_VAR; unset ENV_VAR, ma non farlo in mksho yash( typesetinvece localche per quello) in quanto non funzionerebbe, il unsetsolo annullerebbe il local.

¹ Inoltre, attenzione che in bashlocale ENV_VAR(anche se non impostato) manterrebbe l' attributo export . Quindi, se commandfosse una funzione che assegna un valore a ENV_VAR, la variabile sarebbe disponibile nell'ambiente dei comandi chiamati in seguito. unset ENV_VARcancellerebbe quell'attributo. Oppure potresti usare local +x ENV_VARciò che assicurerebbe anche una tabula rasa (a meno che quella variabile non sia stata dichiarata di sola lettura, ma poi non c'è nulla che tu possa fare al riguardo bash).


1
È una domanda separata, ma che diamine è una variabile d'ambiente con un nome vuoto e come la useresti mai - anche per una sorta di exploit? Non dovresti scrivere un programma che legge l'ambiente e cerca specificamente qualcosa del genere?
Joe,

@Joe, prova ad esempio env '=foo' python -c 'import os; print os.environ[""]'. Non mi aspetto che molte persone vorrebbero impostare una variabile del genere.
Stéphane Chazelas,

9

Non c'è equivalente diretto per quanto ne so; puoi usare una subshell:

(unset ENV_VAR; exec command)

(unset ENV_VAR; exec somecommand)se si desidera essere equivalenti all'originale in termini di efficienza (consumando la subshell). Così com'è, questo aggiunge un fork extra.
Charles Duffy,

1
@Charles in effetti, sebbene alcune shell lo facciano automaticamente poiché commandè l'ultimo comando nell'invocazione della subshell.
Stephen Kitt,

+1 perché in questo modo è semplice digitare per un uso interattivo. Uso i subshells per le modifiche una tantum all'ambiente shell per un one-liner invece di ricordare che lo è env -u.
Peter Cordes,

0

Puoi usare ENV_VAR= command

Questo in realtà non disinserisce la variabile, ma può essere utile in molti casi (gli script di shell di solito usano solo test -nper verificare se è impostata una variabile):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.