Estoy interesado en establecer variables ambientales de una instancia de shell de otra. Entonces decidí investigar un poco. Después de leer una serie de preguntas sobre esto , decidí probarlo.
Engendré dos proyectiles A y B (PID 420), ambos corriendo zsh
. Desde shell AI ejecutó lo siguiente.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
Desde el shell B cuando ejecuto env
puedo ver que la variable FOO está configurada con un valor de barra. Esto me hace pensar que FOO se ha inicializado con éxito en el entorno de shell B. Sin embargo, si trato de imprimir FOO obtengo una línea vacía que implica que no está configurada. Para mí, parece que hay una contradicción aquí.
Esto fue probado tanto en mi propio sistema Arch GNU / Linux como en una máquina virtual Ubuntu. También probé esto en bash
donde la variable ni siquiera apareció en env. Esto, aunque es decepcionante para mí, tiene sentido si el shell almacena en caché una copia de su entorno en el momento de la generación y solo usa eso (lo que se sugirió en una de las preguntas vinculadas). Esto todavía no responde por qué zsh
puede ver la variable.
¿Por qué la salida de echo $FOO
vacío?
EDITAR
Después de la entrada en los comentarios, decidí hacer un poco más de pruebas. Los resultados se pueden ver en las tablas a continuación. En la primera columna está el shell en el que FOO
se inyectó la variable. La primera fila contiene el comando cuyo resultado se puede ver debajo de él. La variable FOO
se inyectó usando: sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Los comandos específicos de zsh: zsh -c '...'
también se probaron con bash. Los resultados fueron idénticos, su producción se omitió por brevedad.
Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Lo anterior parece implicar que los resultados son independientes de la distribución. Esto no me dice mucho más zsh
y bash
maneja la configuración de variables de manera diferente. Además, export FOO
tiene un comportamiento muy diferente en este contexto dependiendo del shell. Esperemos que estas pruebas puedan aclararle algo a alguien más.
zsh -c 'echo $FOO'
(usa comillas simples) en su lugar? ¿Puedes verlo entonces?env
) ven el entorno modificado.zsh
en GDB no lo hace visible como una variable de shell, pero hace que se pase a procesos secundarios (como ha observado), mientras que establecer uno parabash
sí lo hace visible como una variable de shell, ¡pero no hace que se pase a procesos secundarios! Parece que zsh y bash usan diferentes estrategias para administrar variables, con zsh que rastrea variables que no son de entorno y bash almacena todo en su entorno que desinfecta cuando se inicia un hijo (sin subshell).export FOO
enbash
?Respuestas:
La mayoría de los shells no usan la API
getenv()
/setenv()
/putenv()
.Al iniciarse, crean variables de shell para cada variable de entorno. Esos serán almacenados en estructuras internas que necesitan transportar otra información, como si la variable se exporta, solo lectura ... No pueden usar las bibliotecas
environ
para eso.Del mismo modo, y por esa razón, no van a utilizar
execlp()
,execvp()
para ejecutar comandos, pero llamar a laexecve()
llamada al sistema directamente, el cálculo de laenvp[]
matriz en base a la lista de sus variables exportadas.Entonces, en su
gdb
, necesitaría agregar una entrada a esa tabla interna de variables de shells, o posiblemente llamar a la función correcta que lo haría interpretar unexport VAR=value
código para actualizar esa tabla por sí mismo.En cuanto a por qué se ve una diferencia entre
bash
yzsh
cuando se llamasetenv()
engdb
, Sospecho que es porque usted está llamandosetenv()
antes de que los inicializa shell, por ejemplo al entrarmain()
.Notarás
bash
'smain()
isint main(int argc, char* argv[], char* envp[])
(ybash
asigna variables de esos entornosenvp[]
) mientras quezsh
' s esint main(int argc, char* argv[])
yzsh
obtiene las variables en suenviron
lugar.setenv()
modificaenviron
pero no puede modificarenvp[]
en el lugar (solo lectura en varios sistemas, así como las cadenas a las que apuntan estos punteros).En cualquier caso, después de que el shell haya leído
environ
en el inicio, el usosetenv()
sería ineficaz ya que el shell ya no usaenviron
(ogetenv()
) después.fuente