¿Exportar una variable env para que esté disponible en todas las subcapas y se pueda modificar?

22

Supongamos que tengo

export MY_VAR=0

en ~/.bashrc.

Tengo un terminal de gnomo abierto, y en este terminal, cambio el $MY_VARvalor a 200. Entonces, si lo hago

echo $MY_VAR

en este terminal, 200se muestra.

Ahora, abrí otra pestaña en mi terminal de gnome, y hago

echo $MY_VAR

... y en lugar de 200, lo tengo 0.

¿Qué debo hacer para mantener el valor 200 cuando un terminal modifica una variable de entorno, haciendo que esta modificación (configuración de 200) esté disponible para todas las subcapas posteriores y demás? es posible?

Alguien todavía te usa MS-DOS
fuente

Respuestas:

23

Una copia del entorno se propaga a subcapas, por lo que esto funciona:

$ export MY_VAR=200
$ bash
$ echo $MY_VAR
200

pero como se trata de una copia, no puede obtener ese valor hasta el shell principal, al menos no cambiando el entorno.

Parece que realmente quiere ir un paso más allá, que es hacer algo que actúe como una variable global, compartida por shells "hermanos" iniciados por separado del padre, como su nueva pestaña en Gnome Terminal.

Principalmente, la respuesta es "no se puede, porque las variables de entorno no funcionan de esa manera". Sin embargo, hay otra respuesta, que es, bueno, siempre puedes hackear algo. Un enfoque sería escribir el valor de la variable en un archivo, como ~/.myvar, y luego incluirlo en ~/.bashrc. Luego, cada nuevo shell comenzará con el valor leído de ese archivo.

Podría ir un paso más allá: haga que ~/.myvaresté en el formato MYVAR=200y luego configúrelo PROMPT_COMMAND=source ~/.myvar, lo que hará que el valor se vuelva a leer cada vez que obtenga un nuevo mensaje. Todavía no es una variable global compartida, pero está comenzando a actuar así. Sin embargo, no se activará hasta que aparezca un mensaje, lo que, dependiendo de lo que intente hacer, podría ser una limitación seria.

Y luego, por supuesto, lo siguiente es escribir automáticamente los cambios ~/.myvar. Eso se vuelve un poco más complicado, y me detendré en este punto, porque en realidad, las variables de entorno no estaban destinadas a ser un mecanismo de comunicación entre shell, y es mejor encontrar otra forma de hacerlo.

mattdm
fuente
10
Puedo escuchar el cascarón chirriando bajo la tortura
Si lo siento Por eso me detuve. :)
mattdm
"que es hacer algo que actúe como una variable global" - Bueno, de hecho, eso es lo que estaba tratando de lograr. El ~ / .myvar no es bonito, pero funciona. ¿Tienes otra sugerencia?
Alguien todavía te usa MS-DOS
2
Bueno, retrocedamos un poco. ¿Por qué quieres una variable global?
mattdm
1
@mattdm: Tengo algunas "burocracias" que debo obedecer. Uno de ellos es un montón de códigos que necesito confirmar junto con un comentario. Estos códigos están, ahora, en una jerarquía de carpetas (inicio / usuario / proyectos / projectcode / code1 / code2). Hice una función que extrae el código1 y el código2 a los entornos (así que cuando necesito hacer una actividad, simplemente llamo a la función dentro del directorio con los códigos), y ellos, cuando me comprometo, uso vim y hay algunas funciones que lee estos vars y escribe un comentario automáticamente. Creo que usar archivos para eso puede ser una solución.
Alguien todavía te usa MS-DOS
13

Supongamos que tengo export MY_VAR=0adentro ~/.bashrc.

Ese es tu error allí mismo. Debe definir las variables de entorno en ~/.profile, que se leen cuando ~/.bashrcinicia sesión. Se leen cada vez que inicia un shell; cuando comienzas el caparazón interno, se anula MY_VAR. Si no lo hubiera hecho, su variable de entorno se propagaría hacia abajo.

Para obtener más información sobre ~/.bashrcvs ~/.profile, vea mis publicaciones anteriores sobre este tema .

Tenga en cuenta que la propagación hacia arriba (obtener un valor modificado de la subshell automáticamente reflejada en la shell principal) no es posible, punto final.

Gilles 'SO- deja de ser malvado'
fuente
3

No use variables de entorno en absoluto. Usa archivos.

Para evitar que los procesos se interpongan entre sí al actualizar / leer el archivo, use archivos de bloqueo y pequeños scripts de actualización front-end cuyo propósito es actualizar un archivo con $ 1 si no está bloqueado. Los archivos de bloqueo se implementan básicamente verificando si existe un archivo específico (/var/run/yourscript.lck) y si es así, espere a que el archivo desaparezca por un tiempo y falle si no es así. También debe eliminar el archivo de bloqueo cuando termine de actualizar el archivo.

Esté preparado para manejar una situación en la que un script no puede actualizar un archivo porque el archivo está ocupado.

LawrenceC
fuente
8
Un truco: use directorios en lugar de archivos para bloquear, porque mkdirfunciona como una prueba y creación atómica.
mattdm
1
Si quieren hablar sobre el bloqueo, entonces bien podrían estar usandoflock(2)
Ehtesh Choudhury
@mattdm Descubrí que un enlace simbólico ln -s dummy lockfile(incluso si está roto) también puede funcionar, ya que fallará si el enlace simbólico ya existe. Me pregunto alguna forma de probar si eso es realmente 100% seguro.
Acuario Power
1

Cuando acabo de buscar en Google esta pregunta, estaba tratando de resolver el problema de actualizar el estado (es decir, las variables de shell) desde subcapas. Para que uno pueda asignar variables, por ejemplo, dentro de una tubería, y la asignación sería transparente para el padre.

Por supuesto, esto no es posible de una manera simple porque las partes individuales de una tubería se ejecutan en subcapas, que se forkeditan desde el shell principal y, por lo tanto, tienen memoria que es una vista de copia en escritura en la memoria del padre. Sin embargo, supuse que una solución delgada y transparente podría ser posible en base a IPC de " memoria compartida " .

E incluso encontré una implementación de exactamente este diseño ... pero está en Perl.

Agregar esta respuesta de todos modos como una posible solución.

ulidtko
fuente