Saltar al contenido

¿Cuál es la diferencia de uso entre las variables de shell y las variables de entorno?

Nuestro team de especialistas pasados muchos días de investigación y de recopilar de información, dimos con la respuesta, esperamos que te sea útil en tu plan.

Solución:

Variables de shell

Las variables de shell son variables cuyo alcance está en la sesión de shell actual, por ejemplo, en una sesión de shell interactiva o un script.

Puede crear una variable de shell asignando un valor a un nombre no utilizado:

var="hello"

El uso de variables de shell es para realizar un seguimiento de los datos en la sesión actual. Las variables de shell suelen tener nombres con letras minúsculas.

Variables de entorno

Una variable de entorno es una variable de shell que se ha exportado. Esto significa que será visible como una variable, no solo en la sesión de shell que lo creó, sino también para cualquier proceso (no solo shells) que se inicie desde esa sesión.

VAR="hello"  # shell variable created
export VAR   # variable now part of the environment

o

export VAR="hello"

Una vez que se ha exportado una variable de shell, permanece exportada hasta que se desarma o hasta que se elimina su “propiedad de exportación” (con export -n en bash), por lo que normalmente no es necesario volver a exportarlo. Desarmar una variable con unset lo elimina (no importa si es una variable de entorno o no).

Matrices y hashes asociativos en bash y otros shells no pueden exportarse para convertirse en variables de entorno. Las variables de entorno deben ser variables simples cuyos valores sean cadenas y, a menudo, tienen nombres que constan de letras mayúsculas.

El uso de variables de entorno es para realizar un seguimiento de los datos en la sesión de shell actual, pero también para permitir que cualquier proceso iniciado forme parte de esos datos. El caso típico de esto es el PATH variable de entorno, que puede establecerse en el shell y luego ser utilizada por cualquier programa que desee iniciar programas sin especificar una ruta completa a ellos.

La colección de variables de entorno en un proceso a menudo se denomina “el entorno del proceso”. Cada proceso tiene su propio entorno.

Las variables de entorno solo se pueden “reenviar”, es decir, un proceso hijo puede Nunca cambiar las variables de entorno en su proceso padre, y aparte de configurar el entorno para un proceso hijo al iniciarlo, un proceso padre no puede cambiar el entorno existente de un proceso hijo.

Las variables de entorno se pueden enumerar con env (sin argumentos). Aparte de eso, aparecen igual que las variables de shell no exportadas en una sesión de shell. Esto es un poco especial para el shell, ya que la mayoría de los otros lenguajes de programación no suelen mezclar variables “ordinarias” con variables de entorno. (vea abajo).

env también se puede utilizar para establecer los valores de una o varias variables de entorno en el entorno de un proceso sin establecerlos en la sesión actual:

env CC=clang CXX=clang++ make

Esto comienza make con la variable de entorno CC establecer en el valor clang y CXX ajustado a clang++.

También se puede utilizar para claro el entorno para un proceso:

env -i bash

Esto comienza bash pero no transfiere el entorno actual al nuevo bash proceso (todavía tengo variables de entorno a medida que crea nuevas a partir de sus scripts de inicialización de shell).

Ejemplo de diferencia

$ var="hello"   # create shell variable "var"
$ bash          # start _new_ bash session
$ echo "$var"   # no output
$ exit          # back to original shell session
$ echo "$var"   # "hello" is outputted
$ unset var     # remove variable

$ export VAR="hello"  # create environment variable "VAR"
$ bash
$ echo "$VAR"         # "hello" is outputted since it's exported
$ exit                # back to original shell session
$ unset VAR           # remove variable

$ ( export VAR="hello"; echo "$VAR" )  # set env. var "VAR" to "hello" in subshell and echo it
$ echo "$VAR"         # no output since a subshell has its own environment

Otros idiomas

Hay funciones de biblioteca en la mayoría de los lenguajes de programación que permiten obtener y configurar las variables de entorno. Tenga en cuenta que, dado que las variables de entorno se almacenan como una relación clave-valor simple, no suelen ser “variables” del lenguaje. Un programa puede obtener el valor (que siempre es un carácter string) correspondiente a una clave (el nombre de la variable de entorno), pero luego tendrá que convertirla a un número entero o al tipo de datos que el lenguaje espera que tenga el valor.

En C, se puede acceder a las variables de entorno usando getenv(), setenv(), putenv() y unsetenv(). Las variables creadas con estas rutinas son heredadas de la misma manera por cualquier proceso que inicie el programa en C.

Otros lenguajes pueden tener estructuras de datos especiales para lograr lo mismo, como el %ENV hash en Perl, o el ENVIRON de asociación array en la mayoría de las implementaciones de awk.

Las variables de entorno son una lista de name=value pares que existen sea cual sea el programa (shell, aplicación, demonio…). Por lo general, son heredados por procesos secundarios (creados por un fork/exec secuencia): los procesos secundarios obtienen su propia copia de las variables principales.

Las variables de shell existen solo en el contexto de un shell. Solo se heredan en subcapas (es decir, cuando la cáscara se bifurca sin un exec operación). Dependiendo de las características del shell, las variables pueden no solo ser cadenas simples como las del entorno, sino también matrices, compuestas, variables escritas como enteros o de punto flotante, etc.

Cuando se inicia un shell, todas las variables de entorno que hereda de su padre se convierten también en variables de shell (a menos que no sean válidas como variables de shell y otros casos de esquina como IFS que es restablecido por algunos shells) pero estas variables heredadas se etiquetan como exportadas1. Eso significa que permanecerán disponibles para procesos secundarios con el valor potencialmente actualizado establecido por el shell. Ese también es el caso de las variables creadas bajo el shell y etiquetadas como exportadas con el export palabra clave.

La matriz y otras variables de tipo complejo no se pueden exportar a menos que su nombre y valor se puedan convertir al name=value patrón, o cuando un mecanismo específico de shell está en su lugar (por ejemplo: bash exporta funciones en el entorno y algunos shells exóticos que no son POSIX como rc y es puede exportar matrices).

Entonces, la principal diferencia entre las variables de entorno y las variables de shell es su alcance: las variables de entorno son globales, mientras que las variables de shell no exportadas son locales para el script.

Tenga en cuenta también que las conchas modernas (al menos ksh y bash) admiten un tercer ámbito de variables de shell. Variables creadas en funciones con la typeset la palabra clave son locales para esa función (la forma en que se declara la función habilita / deshabilita esta función en ksh, y el comportamiento de persistencia es diferente entre bash y ksh). Ver https://unix.stackexchange.com/a/28349/2594

1Esto se aplica a las conchas modernas como ksh, dash, bash y similares. El shell Bourne heredado y los shells de sintaxis no Bourne como csh tienen diferentes comportamientos.

Las variables de shell son difíciles de duplicar.

$ FOO=bar
$ FOO=zot
$ echo $FOO
zot
$ 

Sin embargo, las variables de entorno se pueden duplicar; son solo una lista y una lista puede tener entradas duplicadas. Aquí está envdup.c para hacer precisamente eso.

#include 
#include 
#include 
#include 

extern char **environ;

int main(int argc, char *argv[]) 
    char **newenv;
    int envcount = 0;

    if (argc < 2) errx(64, "Usage: envdup command [args ..]");

    newenv = environ;
    while (*newenv++ != NULL) envcount++;

    newenv = malloc(sizeof(char *) * (envcount + 3));
    if (newenv == NULL) err(1, "malloc failed");
    memcpy(newenv, environ, sizeof(char *) * envcount);
    newenv[envcount]   = "FOO=bar";
    newenv[envcount+1] = "FOO=zot";
    newenv[envcount+2] = NULL;

    environ = newenv;
    argv++;
    execvp(*argv, argv);
    err(1, "exec failed '%s'", *argv);

Que podemos compilar y ejecutar contando envdup para luego correr env para mostrarnos qué variables de entorno están configuradas ...

$ make envdup
cc     envdup.c   -o envdup
$ unset FOO
$ ./envdup env | grep FOO
FOO=bar
FOO=zot
$ 

Esto quizás solo sea útil para encontrar errores u otras rarezas en lo bien que los programas manejan **environ.

$ unset FOO
$ ./envdup perl -e 'exec "env"' | grep FOO
FOO=bar
$ ./envdup python3 -c 'import os;os.execvp("env",["env"])' | grep FOO
FOO=bar
FOO=zot
$ 

Parece que Python 3.6 aquí pasa ciegamente los duplicados (una abstracción con fugas) mientras que Perl 5.24 no lo hace. ¿Qué hay de las conchas?

$ ./envdup bash -c 'echo $FOO; exec env' | egrep 'bar|zot'
zot
FOO=zot
$ ./envdup zsh -c 'echo $FOO; exec env' | egrep 'bar|zot' 
bar
FOO=bar
$ 

Dios, que pasa si sudo solo desinfecta la primera entrada al entorno, pero luego bash corre con el segundo? Hola PATH o LD_RUN_PATH explotar. Es tuyo sudo (¿y todo lo demás?) ¿remendado para ese agujero? Las vulnerabilidades de seguridad no son "una diferencia anecdótica" ni simplemente "un error" en el programa de llamada.

Puedes secundar nuestra misión dejando un comentario y dejando una puntuación te estamos agradecidos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *