Definir una variable con o sin exportación

956

Lo que es exportpara?

Cuál es la diferencia entre:

export name=value

y

name=value
flybywire
fuente
44
Tangencialmente tenga en cuenta también que export name=valueno es portátil. Dependiendo de lo que quieras exactamente, prueba name=value; export namecon una solución portátil.
tripleee

Respuestas:

1055

export hace que la variable esté disponible para subprocesos.

Es decir,

export name=value

significa que el nombre de la variable está disponible para cualquier proceso que ejecute desde ese proceso de shell. Si desea que un proceso haga uso de esta variable, use exporty ejecute el proceso desde ese shell.

name=value

significa que el alcance variable está restringido al shell y no está disponible para ningún otro proceso. Usaría esto para (digamos) variables de bucle, variables temporales, etc.

Es importante tener en cuenta que exportar una variable no la pone a disposición de los procesos principales. Es decir, especificar y exportar una variable en un proceso generado no la hace disponible en el proceso que la lanzó.

Brian Agnew
fuente
105
Específicamente, la exportación hace que la variable esté disponible para los procesos secundarios a través del entorno.
Beano el
15
También agregaría que si la exportación está en un archivo que usted "origina" (como. Nombre de archivo), también lo exporta a su entorno de trabajo.
rogerdpack
66
@rogerdpack ¿no puedes hacer eso sin exportar? gato> bla \ na = hola \ n. paja; echo $ a; salidas 'hola' para mí.
David Winiecki
2
Agradable funciona incluso sin la exportación. Así que supongo que al comprar un archivo, si se utiliza la exportación que se reflejará en los procesos secundarios, si no se acaba de afectar al medio ambiente local de fiesta ...
rogerdpack
19
Hay un caso extremo para esto; name=value command hace que la variable esté disponible en el subproceso command.
Oliver Charlesworth
254

Para ilustrar lo que dicen las otras respuestas:

$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar

bash-3.2$ 
alxp
fuente
99
Un ejemplo más de estoal$ foobar="Whatever" bash
Alun
70

Otros han respondido que exportar hace que la variable esté disponible para subcapas, y eso es correcto pero simplemente un efecto secundario. Cuando exporta una variable, la coloca en el entorno del shell actual (es decir, el shell llama putenv(3)o setenv(3)).
El entorno de un proceso se hereda a través de exec, lo que hace que la variable sea visible en subcapas.

Editar (con perspectiva de 5 años): esta es una respuesta tonta. El propósito de 'exportar' es hacer que las variables "se encuentren en el entorno de los comandos ejecutados posteriormente", ya sean comandos o subprocesos. Una implementación ingenua sería simplemente poner la variable en el entorno del shell, pero esto haría que sea imposible de implementar export -p.

William Pursell
fuente
66
Tenga en cuenta que esto no es del todo cierto. En bash, export de hecho agrega la variable al entorno del shell actual, pero este no es el caso con dash. Me parece que agregar la variable al entorno del shell actual es la forma más sencilla de implementar la semántica de export, pero ese comportamiento no es obligatorio.
William Pursell
77
No estoy seguro de qué dashtiene que ver esto. El póster original preguntaba específicamente sobre bash.
Starfish
14
La pregunta está etiquetada bashpero se aplica igualmente a cualquier variante de caparazón de bourne. Ser demasiado específico y proporcionar respuestas que se aplican solo a bashes un gran mal.
William Pursell
12
bashes el jQuery del shell.
Potherca
2
export makes the variable available to subshells, and that is correctEste es un uso muy confuso de la terminología. Las subcapas no necesitan exportheredar variables. Los subprocesos sí.
Amit Naidu
62

Se ha dicho que no es necesario exportar en bash cuando se generan subcapas, mientras que otros dicen exactamente lo contrario. Es importante tener en cuenta la diferencia entre subniveles (aquellos que son creados por (), ``, $()o bucles) y subprocesos (procesos que se invocan por su nombre, por ejemplo, un literal bashque aparece en el script).

  • Los shells secundarios tendrán acceso a todas las variables del padre, independientemente de su estado exportado.
  • Sub procesos serán solamente ver las variables exportadas.

Lo que es común en estas dos construcciones es que ninguna de las dos puede devolver variables al shell principal.

$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:

Hay otra fuente de confusión: algunos piensan que los subprocesos 'bifurcados' son los que no ven variables no exportadas. Por lo general, los fork () s son seguidos inmediatamente por exec () s, y es por eso que parece que el fork () es lo que debe buscarse, mientras que de hecho es el exec (). Puede ejecutar comandos sin fork () primero con el execcomando, y los procesos iniciados por este método tampoco tendrán acceso a variables no exportadas:

$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export

Tenga en cuenta que parent:esta vez no vemos la línea, porque hemos reemplazado el shell principal con el execcomando, por lo que no queda nada para ejecutar ese comando.

Matyas Koszik
fuente
Nunca he visto un bucle que (por sí mismo) haya creado una subshell; OTOH lo hace una tubería (siempre para piezas diferentes a la última, a veces para la última dependiendo de su shell, versión y opciones). Backgrounding ( &) también crea una subshell.
dave_thompson_085
¿Qué hay de estos var=asdf bash -c 'echo $var'o var=asdf exec bash -c 'echo $var'? La salida es asdf. La ;diferencia se coloca después de la definición de la variable. ¿Cuál sería la explicación? Parece que el var(sin ;) respecto al subproceso generado de alguna manera, debido a que el shell de origen no tiene nada que ver con eso. echo $varno imprime nada si se ejecuta en la segunda línea. Pero uno alineado var=asdf bash -c 'echo $var'; echo $varda asdf\nasdf.
4xy
31

export NAME=value para configuraciones y variables que tienen significado para un subproceso.

NAME=value para variables temporales o de bucle privadas para el proceso de shell actual.

Con más detalle, exportmarca el nombre de la variable en el entorno que se copia en un subproceso y sus subprocesos en el momento de la creación. Ningún nombre o valor se copia del subproceso.

  • Un error común es colocar un espacio alrededor del signo igual:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
  • El Bsubproceso solo ve la variable exportada ( ):

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
  • Los cambios en el subproceso no cambian el shell principal:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
  • Las variables marcadas para exportación tienen valores copiados cuando se crea el subproceso:

    $ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
    [1] 3306
    $ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash 
    Subprocess 1 has B=Bob
    Subprocess 2 has B=Banana
    [1]+  Done         echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
  • Solo las variables exportadas se vuelven parte del entorno ( man environ):

     $ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
     BOB=Bob

Entonces, ¡ahora debería estar tan claro como el sol del verano! Gracias a Brain Agnew, alexp y William Prusell.

Charles Merriam
fuente
12

export hará que la variable esté disponible para todos los shells bifurcados del shell actual.

John T
fuente
11

Cabe señalar que puede exportar una variable y luego cambiar el valor. El valor modificado de la variable estará disponible para los procesos secundarios. Una vez que se ha establecido la exportación para una variable, debe hacer export -n <var>para eliminar la propiedad.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
Brian S. Wilson
fuente
Gracias, esta es exactamente la información que estaba buscando porque vi un script que usaba variables de entorno y luego las "reexporté" con un nuevo valor, y me preguntaba si era necesario.
Mike Lippert
8

Como ya sabrás, UNIX permite que los procesos tengan un conjunto de variables de entorno, que son pares clave / valor, tanto la clave como el valor son cadenas. El sistema operativo es responsable de mantener estos pares para cada proceso por separado.

El programa puede acceder a sus variables de entorno a través de esta API UNIX:

  • char *getenv(const char *name);
  • int setenv(const char *name, const char *value, int override);
  • int unsetenv(const char *name);

Los procesos también heredan variables de entorno de los procesos primarios. El sistema operativo es responsable de crear una copia de todos los "envars" en el momento en que se crea el proceso secundario.

Bash , entre otros shells, es capaz de configurar sus variables de entorno a petición del usuario. Para eso exportexiste.

exportes un comando Bash para establecer la variable de entorno para Bash. Todas las variables establecidas con este comando serían heredadas por todos los procesos que crearía este Bash.

Más sobre el medio ambiente en Bash

Otro tipo de variable en Bash es la variable interna. Dado que Bash no es solo un shell interactivo, de hecho es un intérprete de script, como cualquier otro intérprete (por ejemplo, Python) es capaz de mantener su propio conjunto de variables. Cabe mencionar que Bash (a diferencia de Python) solo admite variables de cadena.

La notación para definir variables de Bash es name=value. Estas variables permanecen dentro de Bash y no tienen nada que ver con las variables de entorno que mantiene el sistema operativo.

Más sobre los parámetros de Shell (incluidas las variables)

También vale la pena señalar que, de acuerdo con el manual de referencia de Bash:

El entorno para cualquier comando o función simple puede aumentarse temporalmente con el prefijo con asignaciones de parámetros, como se describe en Parámetros de Shell . Estas declaraciones de asignación afectan solo al entorno visto por ese comando.


Para resumir las cosas:

  • exportse usa para establecer la variable de entorno en el sistema operativo. Esta variable estará disponible para todos los procesos secundarios creados por el proceso Bash actual para siempre.
  • La notación de variables bash (nombre = valor) se usa para establecer variables locales disponibles solo para el proceso actual de bash
  • La notación de la variable Bash que antepone otro comando crea una variable de entorno solo para el alcance de ese comando.
progalgo
fuente
1
bash vars no admite tantos tipos como Python, pero tiene una cadena, un entero y dos tipos de matriz ('indexada' / tradicional y 'asociativa' que es similar a awk array, perl hash o Python dict). Otras conchas varían; Solo la cuerda es portátil .
dave_thompson_085
7

La respuesta aceptada implica esto, pero me gustaría hacer explícita la conexión a los componentes integrados de shell:

Como ya se mencionó, exporthará que una variable esté disponible tanto para el shell como para los hijos. Si exportse no se utiliza, la variable sólo estará disponible en la cáscara, y sólo la cáscara órdenes internas se puede acceder a él.

Es decir,

tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin
flow2k
fuente
3

Aquí hay otro ejemplo más:

VARTEST="value of VARTEST" 
#export VARTEST="value of VARTEST" 
sudo env | grep -i vartest 
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}" 
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'  

¡Solo usando export VARTEST el valor de VARTEST está disponible en sudo bash -c '...'!

Para más ejemplos ver:


fuente
3

Dos de los creadores de UNIX, Brian Kernighan y Rob Pike, explican esto en su libro "El entorno de programación de UNIX". Busque el título en Google y encontrará fácilmente una versión en pdf.

Abordan las variables de shell en la sección 3.6 y se centran en el uso del exportcomando al final de esa sección:

Cuando desee que el valor de una variable sea accesible en subcapas, se debe usar el comando de exportación del caparazón. (Puede pensar en por qué no hay forma de exportar el valor de una variable desde un sub-shell a su padre).

Dan Carter
fuente
2

Solo para mostrar la diferencia entre una variable exportada que se encuentra en el entorno (env) y una variable no exportada que no se encuentra en el entorno:

Si hago esto:

$ MYNAME=Fred
$ export OURNAME=Jim

entonces solo $ OURNAME aparece en la env. La variable $ MYNAME no está en el entorno.

$ env | grep NAME
OURNAME=Jim

pero la variable $ MYNAME existe en el shell

$ echo $MYNAME
Fred
Será
fuente
1

Por defecto, las variables creadas dentro de un script solo están disponibles para el shell actual; Los procesos secundarios (subcapas) no tendrán acceso a los valores que se hayan establecido o modificado. Permitir que los procesos secundarios vean los valores requiere el uso del comando de exportación.

Amjad
fuente
0

Aunque no se menciona explícitamente en la discusión, NO es necesario usar exportar cuando se genera una subshell desde adentro de bash ya que todas las variables se copian en el proceso secundario.

Scott
fuente
Por favor, explique que lo que está diciendo parece contradecir directamente las respuestas con los ejemplos anteriores.
Mike Lippert el
¡Esta es la forma correcta si no desea que las variables se exporten globalmente, sino que solo estén disponibles para el subproceso! Gracias.
jtblin