Considere este fragmento:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
Aquí me he puesto $SOMEVAR
a AAA
en la primera línea - y cuando me hago eco de que en la segunda línea, consigo los AAA
contenidos como se esperaba.
Pero luego, si trato de especificar la variable en la misma línea de comando que echo
:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... No obtengo BBB
lo que esperaba, obtengo el valor anterior ( AAA
).
¿Es así como se supone que deben ser las cosas? Si es así, ¿cómo es que puede especificar variables como LD_PRELOAD=/... program args ...
y hacer que funcione? ¿Qué me estoy perdiendo?
bash
environment-variables
echo
sdaau
fuente
fuente
LD_PRELOAD
que funciona es que la variable se establece en el programa de medio ambiente - no en su línea de comandos.Respuestas:
Lo que ves es el comportamiento esperado. El problema es que el shell padre se evalúa
$SOMEVAR
en la línea de comandos antes de invocar el comando con el entorno modificado. Debe obtener la evaluación de$SOMEVAR
diferido hasta que se establezca el entorno.Sus opciones inmediatas incluyen:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.Ambos usan comillas simples para evitar que el shell padre evalúe
$SOMEVAR
; solo se evalúa después de que se establece en el entorno (temporalmente, mientras dure el comando único).Otra opción es usar la notación de sub-shell (como también sugirió Marcus Kuhn en su respuesta ):
(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)
La variable se establece solo en el sub-shell
fuente
El problema, revisado
Francamente, el manual es confuso en este punto. El manual de GNU Bash dice:
Si realmente analiza la oración, lo que está diciendo es que se modifica el entorno para el comando / función, pero no el entorno para el proceso padre. Entonces, esto funcionará:
porque el entorno para el comando env se ha modificado antes de su ejecución. Sin embargo, esto no funcionará:
$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc + TESTVAR=bbb + echo aaa ccc aaa ccc
debido a cuando el shell realiza la expansión de parámetros.
Pasos del intérprete
Otra parte del problema es que Bash define estos pasos para su intérprete:
Lo que está sucediendo aquí es que las incorporaciones no obtienen su propio entorno de ejecución, por lo que nunca ven el entorno modificado. Además, los comandos simples (por ejemplo, / bin / echo) no conseguir una ennvironment modificado (por lo que el ejemplo env trabajó) pero la expansión shell está teniendo lugar en el actual entorno en el paso # 4.
En otras palabras, no está pasando 'aaa $ TESTVAR ccc' a / bin / echo; está pasando la cadena interpolada (como se expandió en el entorno actual) a / bin / echo. En este caso, dado que el entorno actual no tiene TESTVAR , simplemente está pasando 'aaa ccc' al comando.
Resumen
La documentación podría ser mucho más clara. ¡Menos mal que hay Stack Overflow!
Ver también
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
fuente
FOO=foo eval 'echo $FOO'
imprimefoo
como se esperaba. Esto significa que puedes hacer cosas comoIFS="..." read ...
.Para lograr lo que quieres, usa
( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )
Razón:
Debe separar la asignación por punto y coma o una nueva línea del siguiente comando; de lo contrario, no se ejecutará antes de que ocurra la expansión de parámetros para el siguiente comando (eco).
Debe realizar la asignación dentro de un entorno de subshell , para asegurarse de que no persista más allá de la línea actual.
Esta solución es más corta, más ordenada y más eficiente que algunas de las otras sugeridas, en particular, no crea un nuevo proceso.
fuente
(export SOMEVAR=BBB; python -c "from os import getenv; print getenv('SOMEVAR')")
SOMEVAR=BBB python -c "from os import getenv; print getenv('SOMEVAR')"
La razón es que esto establece una variable de entorno para una línea. Pero
echo
no hace la expansión,bash
sí. Por lo tanto, su variable se expande realmente antes de que se ejecute el comando, aunqueSOME_VAR
estéBBB
en el contexto del comando echo.Para ver el efecto, puede hacer algo como:
$ SOME_VAR=BBB bash -c 'echo $SOME_VAR' BBB
Aquí la variable no se expande hasta que se ejecuta el proceso hijo, por lo que verá el valor actualizado. si
SOME_VARIABLE
vuelve a comprobar en el shell principal, sigue siendoAAA
, como se esperaba.fuente
SOMEVAR=BBB; echo zzz $SOMEVAR zzz
Utilizar un ; para separar declaraciones que están en la misma línea.
fuente
LD_PRELOAD
y eso puede funcionar frente a un ejecutable sin punto y coma, aunque ... Muchas gracias de nuevo - ¡salud!Aquí hay una alternativa:
SOMEVAR=BBB && echo zzz $SOMEVAR zzz
fuente
&&
o;
separe los comandos, la asignación persiste, lo que no es el comportamiento deseado de OP. Markus Kuhn tiene la versión correcta de esta respuesta.