Perché non posso usare le variabili come prefisso per un comando per impostare le variabili di ambiente?


11

Normalmente, è possibile impostare una variabile d'ambiente per un comando anteponendolo in questo modo:

hello=hi bash -c 'echo $hello'

So anche che possiamo usare una variabile per sostituire qualsiasi parte di una chiamata di comando come la seguente:

$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"

Sono stato molto sorpreso di scoprire che non è possibile utilizzare una variabile per aggiungere un prefisso a un comando per impostare una variabile di ambiente. Caso di prova:

$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found

Perché non posso impostare la variabile d'ambiente usando una variabile? Il prefisso è una parte speciale? Sono stato in grado di farlo funzionare usando eval di fronte, ma ancora non capisco il perché. Sto usando bash 4.4.


1
È possibile utilizzare envinvece di evalquale IIRC è più sicuro, ma più lento.
wjandrea,

Risposte:


14

Sospetto che questa sia la parte della sequenza che ti sta catturando:

Le parole che non sono assegnazioni variabili o reindirizzamenti vengono espanse (vedere Espansioni della shell). Se dopo l'espansione rimangono delle parole, la prima parola viene considerata il nome del comando e le parole rimanenti sono gli argomenti

Questo è tratto dal manuale di riferimento di Bash nella sezione sull'espansione dei comandi semplici.

Nel cmd=bashesempio, non variabili di ambiente sono impostate, e bash processi linea di comando attraverso l'espansione dei parametri, lasciando bash -c "echo hi".

Nel prefix=hello=hiesempio, ci sono ancora assegnazioni non variabili nel primo passaggio, quindi l'elaborazione continua ad espansione di parametro, risultando in una prima parola di hello=hi.

Una volta che le assegnazioni delle variabili sono state elaborate, non vengono rielaborate durante l'esecuzione del comando.

Vedi l'elaborazione e i suoi risultati sotto set -x:

$ prefix=hello=hi
+ prefix=hello=hi
$ $prefix bash -c 'echo $hello'
+ hello=hi bash -c 'echo $hello'
-bash: hello=hi: command not found
$ hello=42 bash -c 'echo $hello'
+ hello=42
+ bash -c 'echo $hello'
42

Per una variazione più sicura di "espansione variabile" -come- "variabili d'ambiente" rispetto a eval, si consideri il suggerimento di wjandrea dienv :

prefix=hello=hi
env "$prefix" bash -c 'echo "$hello"'
hi

Non è strettamente un'assegnazione di variabili da riga di comando, poiché stiamo usando la envfunzione principale dell'utilità di assegnare variabili di ambiente a un comando, ma raggiunge lo stesso obiettivo. La $prefixvariabile viene espansa durante l'elaborazione della riga di comando, fornendo il nome = valore a env, a chi la passa bash.


3
Allo stesso modo, $foo=bar bash -c ...non funzionerà, perché $foo=barnon è un'assegnazione variabile (qualunque sia il valore di $foo), perché $foo=barnon si adatta allo name=valueschema per l'assegnazione variabile.
Muru,

3

Perché $prefixnon è un compito. @Jeff ha la spiegazione più lunga .

Invece potresti fare una cosa simile con una funzione:

$ prefix() { hello=hi "$@"; }
$ prefix bash -c 'echo "$hello"'
hi

... e puoi anche impilarli, se ti piace:

$ foo() { foo=123 "$@"; }
$ bar() { bar=456 "$@"; }
$ foo bar bash -c 'echo "$bar $foo"'
456 123
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.