En Bash, ¿qué diferencia hay entre las siguientes tres instrucciones?
VARIABLE=valor instrucción
VARIABLE=valor; instrucción
export VARIABLE=valor; instrucción
¿Por qué no todas las combinaciones funcionan cuando se invoca Make y por qué no todas las combinaciones funcionan con echo?
Asignar una variable puede afectar a una de dos: al ambiente o a las variables del shell. Pero ¿cuál afecta a cuál? Para acabar de complicar la situación, en algunos casos es un cambio persistente y en otros es un cambio temporal.
Para salir de la duda de una vez por todas y entender con exactitud lo que ocurre, he preparado una dupla de pruebas para cada una de las 3 sintaxis, resultando en 6 combinaciones:
VAR=val env | grep VAR; env | grep VAR
VAR=val; env | grep VAR; env | grep VAR
export VAR=val; env | grep VAR; env | grep VAR
VAR=val echo $VAR; echo $VAR
VAR=val; echo $VAR; echo $VAR
export VAR=val; echo $VAR; echo $VAR
Estas pruebas deberían ser suficientes para salir de la duda. Para asegurar la fiabilidad a las pruebas, cada una la envolví de esta forma, que permitirá, incluso, ver los saltos de línea:
(unset VAR; PRUEBA) | tr '\n' :; echo
Resultados:
VAR=val instr | VAR=val; instr | export VAR=val; instr | |
echo $VAR; echo $VAR | :: | val:val: | val:val: |
env | grep VAR; env | grep VAR | VAR=val: | (línea vacía) | VAR=val:VAR=val: |
Se concluye lo siguiente:
VAR=val instr | VAR=val; instr | export VAR=val; instr | |
Alcance | Sólo para la instrucción especificada | A partir de este momento | A partr de este momento |
Ambiente al que afecta | Subproceso | Shell actual | Shell actual y subproceso |
Tiene sentido:
En la sintaxis VAR=val instr
, la asignación es un prefijo para instr
y sólo para instr
. Lo interesante es que sólo afecta al ambiente exportado a la instrucción. Es decir, VAR=val echo $VAR
no funciona porque la variable la expande Bash mismo antes de asignar el valor val a VAR. En efecto: VAR=val1; VAR=val2 echo $VAR
regresa val1
.
En la sintaxis VAR=val; instr
, el punto y coma efectivamente separa una instrucción de la otra. Es el equivalente de asignar el valor val a VAR antes que cualquier otra instrucción como una acción independiente; es una acción independiente. Esto le da la persistencia del valor tanto en esta sinaxis como en la tercera. Además, Bash, por defecto, no exporta sus variables al entorno. Esto hace que sólo se afecte la instrucción echo… O bueno… en realidad no, no es echo quien se está viendo afectado. Ojo: Echo no recibe la variable en su entorno: es Bash quien está expandiendo la variable a su valor al llamar echo, quien recibe el valor ya expandido como argumento.
La tercera sintaxis, export VAR=val; instr
es igual a la segunda: dos instrucciones independientes, con la adición de que la instrucción export
, naturalmente interna a Bash, indica que VAR se debe exportar al ambiente de los siguientes subprocesos. Es decir, tanto se asigna como se importa en la misma instrucción. Es por esto que afecta tanto a echo $VAR
como a env
, Make y lo que se ponga a su paso.
Siendo dos aspectos afectados y dos puntos a combinar podría pensarse que falta una cuarta sintaxis: export VAR=val instr
, sin el punto y coma. Sin embargo, esta sintaxis es una simple invocación a export, indicando que queremos exportar las variables VAR
e instr
.