Me encontré con un problema que me muestra que no tengo claro el alcance de las variables de shell.
Estaba tratando de usar bundle install
, que es un comando Ruby que usa el valor de $GEM_HOME
para hacer su trabajo. Lo había configurado $GEM_HOME
, pero el comando ignoró ese valor hasta que lo usé export
, como en export GEM_HOME=/some/path
.
Leí que esto hace que la variable sea de alguna manera "global" (también conocida como variable de entorno ), pero no entiendo lo que eso significa. Sé acerca de los globales en la programación, pero no a través de distintos programas.
Además, dado que mi configuración de tales variables se aplica solo a la sesión de shell actual, ¿cómo las establecería para, por ejemplo, un proceso demonizado?
¿Qué ámbitos pueden tener las variables de shell?
fuente
FOO=bar
, eso establece el valor para el proceso actual del shell. Si luego ejecuto un programa como (bundle install
), eso crea un proceso secundario, al que no tiene accesoFOO
. Pero si hubiera dichoexport FOO=bar
, el proceso hijo (y sus descendientes) tendrían acceso a él. Uno de ellos podría, a su vez, llamarexport FOO=buzz
para cambiar el valor de sus descendientes, o simplementeFOO=buzz
para cambiar el valor solo para sí mismo. ¿Eso es correcto?Al menos bajo
ksh
ybash
, las variables pueden tener tres ámbitos, no dos como todas las respuestas restantes están diciendo actualmente.Además de la variable exportada (es decir, de entorno) y los ámbitos de variables de shell no exportados, también hay una tercera más estrecha para las variables locales de función.
Las variables declaradas en funciones de shell con el
typeset
token solo son visibles dentro de las funciones en las que se declaran y en (sub) funciones llamadas desde allí.Este
ksh
/bash
código:produce esta salida:
Como puede ver, la variable exportada se muestra desde las tres primeras ubicaciones, las variables no exportadas no se muestran fuera del shell actual y la variable local de la función no tiene ningún valor fuera de la función misma. La última prueba no muestra ningún valor, esto se debe a que las variables exportadas no se comparten entre shells, es decir, solo pueden heredarse y el valor heredado no puede verse afectado posteriormente por el shell padre.
Tenga en cuenta que este último comportamiento es bastante diferente del de Windows, donde puede usar variables del sistema que son totalmente globales y compartidas por todos los procesos.
fuente
Son alcanzados por proceso
Los otros respondedores me ayudaron a comprender que el alcance variable de shell se trata de procesos y sus descendientes .
Cuando escribe un comando como
ls
en la línea de comando, en realidad está bifurcando un proceso para ejecutar ells
programa. El nuevo proceso tiene su shell como padre.Cualquier proceso puede tener sus propias variables "locales", que no se pasan a los procesos secundarios. También puede establecer variables de "entorno", que son. El uso
export
crea una variable de entorno. En cualquier caso, los procesos no relacionados (pares del original) no verán la variable; solo estamos controlando lo que ven los procesos secundarios.Supongamos que tiene un shell bash, al que llamaremos A. Usted escribe
bash
, lo que crea un shell bash de proceso hijo, al que llamaremos B. Cualquier cosa que haya llamadoexport
en A todavía se establecerá en B.Ahora, en B, dices
FOO=b
. Sucederá una de dos cosas:FOO
, creará una variable local. Los niños de B no lo recibirán (a menos que B llameexport
).FOO
, se modificarlo para sí y sus hijos posteriormente bifurcadas . Los hijos de B verán el valor que B asignó. Sin embargo, esto no afectará a A en absoluto.Aquí hay una demostración rápida.
Todo esto explica mi problema original: configuré
GEM_HOME
mi shell, pero cuando llamébundle install
, eso creó un proceso secundario. Como no lo había usadoexport
, el proceso hijo no recibió el shellGEM_HOME
.No exportar
Puede "desexportar" una variable, evitando que se pase a los niños, mediante el uso
export -n FOO
.fuente
La mejor explicación que puedo encontrar sobre la exportación es esta:
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
La variable establecida dentro de un subshell o un shell hijo solo es visible para el subshell en el que se define. La variable exportada está hecha para ser una variable de entorno. Entonces, para ser claros,
bundle install
ejecuta su propio shell, que no ve a$GEM_HOME
menos que se convierta en unaenvironment
variable también conocida como exportada.Puede echar un vistazo a la documentación para el alcance variable aquí:
http://www.tldp.org/LDP/abs/html/subshells.html
fuente
FOO=bar
; tienes que usarexport
para hacerlo uno. Pregunta corregida en consecuencia.Hay una jerarquía de ámbitos variables, como se esperaba.
Medio ambiente
El alcance más externo es el medio ambiente. Este es el único alcance administrado por el sistema operativo y, por lo tanto, se garantiza que existe para cada proceso. Cuando se inicia un proceso, recibe una copia del entorno de su padre después de lo cual los dos se vuelven independientes: modificar el entorno del niño no cambia el del padre y modificar el entorno del padre no cambia el de un niño ya existente.
Variables de Shell
Los shells tienen su propia noción de variables. Aquí es donde las cosas comienzan a ser un poco confusas.
Cuando asigna un valor a una variable en un shell, y esa variable ya existe en el entorno, la variable de entorno recibe el nuevo valor. Sin embargo, si la variable aún no está en el entorno, se convierte en una variable de shell . Las variables de shell solo existen dentro del proceso de shell, de forma similar a como las variables de Ruby solo existen dentro de un script de Ruby. Nunca son heredados por procesos hijos.
Aquí es donde
export
entra en juego la palabra clave. Copia una variable de shell en el entorno del proceso de shell, lo que hace posible que los procesos secundarios hereden.Variables locales
Las variables locales son variables de shell en los bloques de código que las contienen. Usted declara variables locales con la
typeset
palabra clave (portable) olocal
odeclare
(Bash). Al igual que otras variables de shell, los procesos secundarios no heredan las variables locales. Tampoco se pueden exportar variables locales.fuente