Se corro
export TEST=foo
echo $TEST
Emette foo.
Se corro
TEST=foo echo $TEST
Non è così. Come posso ottenere questa funzionalità senza usare l'esportazione o uno script?
Se corro
export TEST=foo
echo $TEST
Emette foo.
Se corro
TEST=foo echo $TEST
Non è così. Come posso ottenere questa funzionalità senza usare l'esportazione o uno script?
Risposte:
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à.
export
farà 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
$TEST
prima che venga eseguita la riga di comando. Una volta che echo
è in esecuzione (nota anche che di echo
solito si tradurrà nel comando incorporato della shell e non in /bin/echo
) vedrà la variabile impostata nel suo ambiente. Tuttavia, echo $TEST
non dice echo
di produrre il contenuto della variabile TEST
dal suo ambiente. Indica alla shell di funzionare echo
con l'argomento qualsiasi cosa sia attualmente nella variabile chiamata TEST
- e queste sono due cose molto diverse.
var=value sh -c 'echo "$var"'
?
"… $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 -c
shell new ( ) senza essere interpretata dalla shell interattiva esterna. ... (proseguendo)
sh -c
shell child nuova ( ).
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=value
stringa all'ambiente che riceve l'eco. Tuttavia, echo
non 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=value
al sh
comando e sh
ci capita di usare il suo ambiente. Le conchiglie convertono ciascuna delle variabili che ricevono dal loro ambiente in una variabile di shell, quindi la var
variabile di ambiente sh
ricevuta verrà convertita in una $var
variabile e, quando la espanderà in quella echo
riga di comando, diventerà echo value
. Poiché l'ambiente è ereditato per impostazione predefinita, echo
riceverà anche var=value
nel suo ambiente (o lo farebbe se fosse eseguito), ma ancora una volta echo
non 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
/ ksh
emulazione):
var=value command eval 'echo "1: $var"'; echo "2: $var"
(l'uso command
di 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))
Lo stai facendo correttamente, ma la sintassi bash è facile da interpretare erroneamente: potresti pensare che echo $TEST
causi il echo
recupero di TEST
env var e poi la stampa, non lo fa. Così dato
export TEST=123
poi
TEST=456 echo $TEST
comporta la seguente sequenza:
La shell analizza l'intera riga di comando ed esegue tutte le sostituzioni variabili, quindi la riga di comando diventa
TEST=456 echo 123
Crea le variabili temporanee impostate prima del comando, quindi salva il valore corrente di TEST
e lo sovrascrive con 456; la riga di comando è ora
echo 123
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
)
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
>>
printenv
utile per il testing / proof of concept (si comporta come una sceneggiatura, al contrario di echo
)
Puoi farlo funzionare usando:
TEST=foo && echo $TEST
TEST=foo
viene eseguito come un'istruzione separata - non è solo impostato nel contesto di echo
.