Come imposto una variabile d'ambiente sulla riga di comando e la faccio apparire nei comandi?


Risposte:


180

Questo perché la shell espande la variabile nella riga di comando prima che esegua effettivamente il comando e in quel momento la variabile non esiste. Se usi

TEST=foo; echo $TEST

Funzionerà.

exportfarà apparire la variabile nell'ambiente dei comandi eseguiti successivamente (per come funziona in bash vedere help export). Se hai solo bisogno che la variabile appaia nell'ambiente di un comando, usa quello che hai provato, cioè:

TEST=foo your-application

1
Che dire di / usr / bin / env? non funziona neanche, sai perché?
Benubird,

5
Lo stesso motivo: la shell si espande $TESTprima che venga eseguita la riga di comando. Una volta che echoè in esecuzione (nota anche che di echosolito si tradurrà nel comando incorporato della shell e non in /bin/echo) vedrà la variabile impostata nel suo ambiente. Tuttavia, echo $TESTnon dice echodi produrre il contenuto della variabile TESTdal suo ambiente. Indica alla shell di funzionare echocon l'argomento qualsiasi cosa sia attualmente nella variabile chiamata TEST- e queste sono due cose molto diverse.
peterph

@peterph Se la shell espande la variabile nella riga di comando prima che esegua effettivamente il comando, perché non la espande var=value sh -c 'echo "$var"'?
Accade il

Come ti ho spiegato qui : è perché le variabili sono espanse tra virgolette doppie (ad esempio, "… $var …") ma non all'interno di virgolette singole (ad esempio, '… $var …'). Poiché echo "$var"è racchiuso tra virgolette singole, l'intera stringa viene passata alla sh -cshell new ( ) senza essere interpretata dalla shell interattiva esterna. ... (proseguendo)
G-Man,

( Proseguendo ) ... Come ha detto igal ieri , ci sono due turni di analisi - anche se credo che igal abbia frainteso la tua domanda. Non ci sono due round di analisi a parte l'analisi eseguita dalla shell genitore. Esistono due cicli di analisi: uno eseguito dalla shell esterna (parent) esterna e uno dalla sh -cshell child nuova ( ).
G-Man,

39

Ho il sospetto che tu voglia avere variabili shell per avere un ambito limitato, piuttosto che variabili d'ambiente. Le variabili di ambiente sono un elenco di stringhe passate ai comandi quando vengono eseguite .

Nel

var=value echo whatever

Stai passando la var=valuestringa all'ambiente che riceve l'eco. Tuttavia, echonon fa nulla con il suo elenco di ambienti e comunque nella maggior parte delle shell, echoè integrato e quindi non eseguito .

Se tu avessi scritto

var=value sh -c 'echo "$var"'

Sarebbe stata un'altra cosa. Qui, stiamo passando var=valueal shcomando e shci capita di usare il suo ambiente. Le conchiglie convertono ciascuna delle variabili che ricevono dal loro ambiente in una variabile di shell, quindi la varvariabile di ambiente shricevuta verrà convertita in una $varvariabile e, quando la espanderà in quella echoriga di comando, diventerà echo value. Poiché l'ambiente è ereditato per impostazione predefinita, echoriceverà anche var=valuenel suo ambiente (o lo farebbe se fosse eseguito), ma ancora una volta echonon si preoccupa dell'ambiente.

Ora, se come sospetto, quello che vuoi è limitare l'ambito delle variabili della shell, ci sono diversi approcci possibili.

Portabilmente (Bourne e POSIX):

(var=value; echo "1: $var"); echo "2: $var"

Il (...) sopra avvia una sotto-shell (un nuovo processo di shell nella maggior parte delle shell), quindi qualsiasi variabile dichiarata lì avrà effetto solo su quella sotto-shell, quindi mi aspetto che il codice sopra produca "1: valore" e "2:" o "2: whatever-var-was-set-to-before".

Con la maggior parte delle shell tipo Bourne, è possibile utilizzare le funzioni e il builtin "locale":

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

Con zsh, puoi usare le funzioni inline:

(){ local var=value; echo "1: $var"; }; echo "2: $var"

o:

function { local var=value; echo "1: $var"; }; echo "2: $var"

Con bash e zsh (ma non ash, pdksh o AT&T ksh), questo trucco funziona anche:

var=value eval 'echo "1: $var"'; echo "2: $var"

Una variante che funziona in un paio di gusci ( dash, mksh, yash), ma non zsh(a meno che in sh/ kshemulazione):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(l'uso commanddi fronte a un builtin speciale (qui eval) nelle shell POSIX ne rimuove la particolarità (qui che le assegnazioni delle variabili da esse rimangono attive dopo che sono tornate))


Per i miei scopi, questa è la soluzione corretta. Non voglio che la variabile 'var' inquini l'ambiente come nella risposta accettata.
kronenpj,

6

Lo stai facendo correttamente, ma la sintassi bash è facile da interpretare erroneamente: potresti pensare che echo $TESTcausi il echorecupero di TESTenv var e poi la stampa, non lo fa. Così dato

export TEST=123

poi

TEST=456 echo $TEST

comporta la seguente sequenza:

  1. La shell analizza l'intera riga di comando ed esegue tutte le sostituzioni variabili, quindi la riga di comando diventa

    TEST=456 echo 123
  2. Crea le variabili temporanee impostate prima del comando, quindi salva il valore corrente di TESTe lo sovrascrive con 456; la riga di comando è ora

    echo 123
  3. Esegue il comando rimanente, che in questo caso stampa 123 su stdout (quindi il comando shell che rimane non ha nemmeno usato il valore temporaneo di TEST)

  4. Ripristina il valore di TEST

Utilizzare invece printenv, poiché non comporta la sostituzione di variabili:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>

+1 Ho trovato printenvutile per il testing / proof of concept (si comporta come una sceneggiatura, al contrario di echo)
Daryn

5

Puoi farlo funzionare usando:

TEST=foo && echo $TEST

6
In questo caso, TEST=fooviene eseguito come un'istruzione separata - non è solo impostato nel contesto di echo.
codeforester
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.