valore temporaneo dello script bash su comando


11

Come sotto il comando,

if true; then
   IFS=":" read a b c d e f <<< "$test"

Il libro dice quando IFS ":"viene utilizzato il comando di assegnazione del valore ( ) prima del comando principale ( read a b c d e f <<< "$value"), il suo valore è temporaneamente attivo sul comando principale. Quindi, il readcomando usa delimitatore :.

Ma, come questo comando,

if true; then
   HOME="hello" echo "$HOME"

Il messaggio Echo non è ciao. Qual è il vero significato del comando precedente?

Risposte:


5

Questo si riduce a una domanda su come funziona la valutazione. Entrambi gli esempi funzionano allo stesso modo, il problema si verifica a causa di come la shell (bash, qui) espande le variabili.

Quando scrivi questo comando:

HOME="foo" echo $HOME

La $HOMEsi espande prima che il comando viene eseguito . Pertanto, viene espanso al valore originale e non a quello nuovo impostato per il comando. La HOMEvariabile è stata effettivamente modificata nell'ambiente in cui echoè in esecuzione il comando, tuttavia, si sta stampando $HOMEdal genitore.

Per illustrare, considerare questo:

$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon

Come puoi vedere sopra, il primo comando stampa il valore temporaneamente modificato di HOMEe il secondo stampa l'originale, dimostrando che la variabile è stata modificata solo temporaneamente. Poiché il bash -c ...comando è racchiuso tra virgolette singole ( ' ') anziché doppie ( " "), la variabile non viene espansa e viene passata così com'è al nuovo processo bash. Questo nuovo processo lo espande e stampa il nuovo valore su cui è stato impostato. Puoi vedere che succede se usi set -x:

$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello         
+ echo hello
hello

Come puoi vedere sopra, la variabile $HOME non viene mai passata a echo. Vede solo il suo valore espanso. Confrontare con:

$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello

Qui, a causa delle virgolette singole, la variabile e non il suo valore vengono passati al nuovo processo.


7

Quando la shell sta analizzando una linea, tokenizzerà la linea in parole, eseguirà varie espansioni (in ordine) sulle parole, quindi eseguirà il comando.

supporre test=1:2:3:4:5:6

Diamo un'occhiata a questo comando: IFS=":" read a b c d e f <<< "$test"

Dopo la tokenizzazione, si verifica l' espansione dei parametri :IFS=":" read a b c d e f <<< "1:2:3:4:5:6"

La shell imposterà la variabile IFS per la durata del comando read e readsaprà applicare $ IFS al suo input e dare valori ai nomi delle variabili.

Questo comando ha una storia simile, ma risultati diversi: HOME="hello" echo "$HOME"

Poiché l'espansione dei parametri avviene prima dell'inizio del comando, la shell ha:

HOME="hello" echo "/home/username"

E poi, durante l'esecuzione del comando echo, il nuovo valore di $ HOME non viene utilizzato affatto.

Per ottenere ciò che stai cercando di fare, scegline uno

# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'

o

# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")

ma non scegliere il primo.


Probabilmente è meglio scegliere il primo. Almeno è significativamente più veloce. Quando eval è la risposta, a volte probabilmente stai ponendo la domanda sbagliata. Ma se qualcuno deve farlo per alcuni motivi, cambiare la risposta non rende la domanda stessa meno sbagliata. Un'altra soluzione è quella di avvolgerlo in una funzione e utilizzare local.
— user23013,

Perché la evalsoluzione dovrebbe essere evitata?
— DarkHeart,

Se non controlli rigorosamente l'input, devi fare molta attenzione al codice che permetti ad altre persone di iniettare nel tuo programma.
— Glenn Jackman,

-1

Esistono due ambiti: variabili di ambiente e variabili locali. Le variabili di ambiente sono valide per ogni processo (vedi setenv, getenv), mentre le variabili locali sono attive solo all'interno di questa sessione di shell. (Non è una distinzione ovvia ...)

Implicito env(come nel tuo esempio) modifica l'ambiente, mentre echo ...usa quelli locali, quindi envnon ha alcun effetto.

Per modificare le variabili locali usare, diciamo,

( HOME="foo" ; echo "$HOME" )

Qui le parentesi definiscono l'ambito di questo incarico.


1
Questo non ha nulla a che fare con l'ambito delle variabili, il problema è che la variabile viene espansa prima di essere passata alla shell figlio.
— terdon
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.