Introducción
Cuando se interactúa con el servidor a través de una sesión de shell, hay muchas piezas de información que el shell compila para determinar su comportamiento y el acceso a los recursos. Algunos de estos ajustes están contenidos dentro de los ajustes de configuración y otros están determinados por la entrada del usuario.
Una forma en que el shell mantiene un registro de todos estos ajustes y detalles es a través de un área que mantiene llamada el entorno. El entorno es un área que el shell construye cada vez que inicia una sesión y que contiene variables que definen las propiedades del sistema.
En esta guía, hablaremos de cómo interactuar con el entorno y leer o establecer las variables de entorno y del shell de forma interactiva y a través de los archivos de configuración.
Cómo funcionan el entorno y las variables de entorno
Cada vez que se inicia una sesión del shell, se lleva a cabo un proceso para reunir y compilar la información que debe estar disponible para el proceso del shell y sus procesos hijos. Obtiene los datos para estas configuraciones de una variedad de archivos y configuraciones diferentes en el sistema.
El entorno proporciona un medio a través del cual el proceso del shell puede obtener o establecer configuraciones y, a su vez, pasarlas a sus procesos hijos.
El entorno se implementa como cadenas que representan pares clave-valor. Si se pasan varios valores, suelen estar separados por caracteres de dos puntos (:
). Cada par tendrá generalmente un aspecto similar al siguiente:
KEY=value1:value2:...
Si el valor contiene espacios en blanco significativos, se utilizan comillas:
KEY="value with spaces"
Las claves en estos escenarios son variables. Pueden ser de dos tipos, variables de entorno o variables de shell.
Las variables de entorno son variables que se definen para el shell actual y son heredadas por cualquier shell o proceso hijo. Las variables de entorno se utilizan para pasar información a los procesos que se generan desde el shell.
Las variables de shell son variables que están contenidas exclusivamente dentro del shell en el que se establecieron o definieron. Suelen utilizarse para hacer un seguimiento de los datos efímeros, como el directorio de trabajo actual.
Por convención, este tipo de variables suelen definirse utilizando todas las letras mayúsculas. Esto ayuda a los usuarios a distinguir las variables de entorno dentro de otros contextos.
Impresión de variables de shell y de entorno
Cada sesión de shell mantiene un registro de sus propias variables de shell y de entorno. Podemos acceder a ellas de diferentes maneras.
Podemos ver una lista de todas nuestras variables de entorno utilizando los comandos env
o printenv
. En su estado por defecto, deberían funcionar exactamente igual:
- printenv
Esto es bastante típico de la salida de ambos printenv
y env
. La diferencia entre ambos comandos sólo es evidente en su funcionalidad más específica. Por ejemplo, con printenv
, puedes solicitar los valores de variables individuales:
- printenv SHELL
Output/bin/bash
Por otro lado, env
te permite modificar el entorno en el que se ejecutan los programas pasando un conjunto de definiciones de variables a un comando como este:
- env VAR1="value" command_to_run command_options
Dado que, como aprendimos anteriormente, los procesos hijos suelen heredar las variables de entorno del proceso padre, esto te da la oportunidad de anular valores o añadir variables adicionales para el hijo.
Como puedes ver en la salida de nuestro comando printenv
, hay bastantes variables de entorno configuradas a través de nuestros archivos y procesos del sistema sin nuestra entrada.
Esto muestra las variables de entorno, pero ¿cómo vemos las variables del shell?
Para ello se puede utilizar el comando set
. Si escribimos set
sin ningún parámetro adicional, obtendremos una lista de todas las variables del shell, las variables de entorno, las variables locales y las funciones del shell:
- set
Esta suele ser una lista enorme. Probablemente quieras canalizarla en un programa paginador para manejar más fácilmente la cantidad de salida:
- set | less
La cantidad de información adicional que recibimos de vuelta es un poco abrumadora. Probablemente no necesitemos conocer todas las funciones de bash que se definen, por ejemplo.
Podemos limpiar la salida especificando que set
debe operar en modo POSIX, que no imprimirá las funciones del shell. Podemos ejecutar esto en un sub-shell para que no cambie nuestro entorno actual:
- (set -o posix; set)
Esto listará todas las variables de entorno y del shell que están definidas.
Podemos intentar comparar esta salida con la salida de los comandos env
o printenv
para intentar obtener una lista sólo de las variables del shell, pero esto será imperfecto debido a las diferentes formas en que estos comandos emiten la información:
- comm -23 <(set -o posix; set | sort) <(env | sort)
Esto probablemente aún incluirá algunas variables de entorno, debido a que el comando set
emite valores entre comillas, mientras que los comandos printenv
y env
no citan los valores de las cadenas.
Esto debería darte una buena idea de las variables de entorno y de shell que se establecen en tu sesión.
Estas variables se utilizan para todo tipo de cosas. Proporcionan una forma alternativa de establecer valores persistentes para la sesión entre procesos, sin escribir los cambios en un archivo.
Variables de entorno y de shell comunes
Algunas variables de entorno y de shell son muy útiles y se referencian con bastante frecuencia.
Aquí hay algunas variables de entorno comunes con las que te encontrarás:
-
SHELL
: Esto describe el shell que interpretará cualquier comando que escribas. En la mayoría de los casos, será bash por defecto, pero se pueden establecer otros valores si se prefieren otras opciones. -
TERM
: Especifica el tipo de terminal a emular cuando se ejecuta el shell. Se pueden emular diferentes terminales de hardware para diferentes requisitos de funcionamiento. Sin embargo, normalmente no tendrá que preocuparse por esto. -
USER
: El usuario actual conectado. -
PWD
: El directorio de trabajo actual. -
OLDPWD
: El directorio de trabajo anterior. Esto lo mantiene el shell para poder volver a su directorio anterior ejecutandocd -
. -
LS_COLORS
: Esto define códigos de colores que se utilizan para añadir opcionalmente salida de color al comandols
. Esto se utiliza para distinguir diferentes tipos de archivos y proporcionar más información al usuario de un vistazo. -
MAIL
: La ruta del buzón del usuario actual. -
PATH
: Una lista de directorios que el sistema comprobará cuando busque comandos. Cuando un usuario escribe un comando, el sistema comprobará los directorios en este orden para el ejecutable. -
LANG
: El idioma actual y la configuración de localización, incluyendo la codificación de caracteres. -
HOME
: El directorio de inicio del usuario actual. -
_
: El comando más reciente ejecutado previamente. -
BASHOPTS
: La lista de opciones que se utilizaron cuando se ejecutó bash. Esto puede ser útil para saber si el entorno de la shell funcionará de la forma que se desea. -
BASH_VERSION
: La versión de bash que se está ejecutando, en forma legible para los humanos. -
BASH_VERSINFO
: La versión de bash, en salida legible por máquina. -
COLUMNS
: El número de columnas de ancho que se están utilizando para dibujar la salida en la pantalla. -
DIRSTACK
: La pila de directorios que están disponibles con los comandospushd
ypopd
. -
HISTFILESIZE
: Número de líneas del historial de comandos almacenadas en un archivo. -
HISTSIZE
: Número de líneas del historial de comandos permitidas en la memoria. -
HOSTNAME
: El nombre de host del ordenador en este momento. -
IFS
: El separador de campo interno para separar la entrada en la línea de comandos. Por defecto, es un espacio. -
PS1
: La definición del prompt de comandos principal. Se utiliza para definir el aspecto del prompt cuando se inicia una sesión de shell. ElPS2
se utiliza para declarar avisos secundarios para cuando un comando abarca varias líneas. -
SHELLOPTS
: Opciones del shell que se pueden establecer con la opciónset
. -
UID
: El UID del usuario actual.
Además de estas variables de entorno, algunas variables del shell que verás a menudo son:
Configuración de variables de shell y de entorno
Para entender mejor la diferencia entre las variables de shell y de entorno, y para introducir la sintaxis para configurar estas variables, haremos una pequeña demostración.
Creación de variables de shell
Comenzaremos definiendo una variable de shell dentro de nuestra sesión actual. Esto es fácil de lograr; sólo necesitamos especificar un nombre y un valor. Nos adheriremos a la convención de mantener todas las mayúsculas para el nombre de la variable, y establecerlo en una cadena simple.
- TEST_VAR='Hello World!'
Aquí, hemos utilizado comillas ya que el valor de nuestra variable contiene un espacio. Además, hemos utilizado comillas simples porque el signo de exclamación es un carácter especial en el shell de bash que normalmente se expande al historial de bash si no se escapa o se pone entre comillas simples.
Ahora tenemos una variable de shell. Esta variable está disponible en nuestra sesión actual, pero no se pasará a los procesos hijos.
Podemos ver esto buscando nuestra nueva variable dentro de la salida set
:
- set | grep TEST_VAR
OutputTEST_VAR='Hello World!'
Podemos comprobar que no se trata de una variable de entorno probando lo mismo con printenv
:
- printenv | grep TEST_VAR
No debería devolverse ninguna salida.
Aprovechemos esto para demostrar una forma de acceder al valor de cualquier variable del shell o del entorno.
- echo $TEST_VAR
OutputHello World!
Como puedes ver, referencia el valor de una variable precediéndola de un signo $
. El shell toma esto para significar que debe sustituir el valor de la variable cuando se encuentra con esto.
Así que ahora tenemos una variable del shell. No debe pasarse a ningún proceso hijo. Podemos generar un nuevo shell bash desde el actual para demostrarlo:
- bash
- echo $TEST_VAR
Si escribimos bash
para generar un shell hijo, y luego intentamos acceder al contenido de la variable, no se devolverá nada. Esto es lo que esperábamos.
Volvemos a nuestro shell original escribiendo exit
:
- exit
Creación de variables de entorno
Ahora, vamos a convertir nuestra variable de shell en una variable de entorno. Podemos hacerlo exportando la variable. El comando para hacerlo se llama apropiadamente:
- export TEST_VAR
Esto cambiará nuestra variable en una variable de entorno. Podemos comprobarlo revisando de nuevo nuestro listado de entorno:
- printenv | grep TEST_VAR
OutputTEST_VAR=Hello World!
Esta vez, nuestra variable aparece. Probemos de nuevo nuestro experimento con nuestra shell hija:
- bash
- echo $TEST_VAR
OutputHello World!
¡Genial! Nuestro shell hijo ha recibido la variable establecida por su padre. Antes de salir de este shell hijo, vamos a intentar exportar otra variable. Podemos establecer variables de entorno en un solo paso así:
- export NEW_VAR="Testing export"
Prueba que se exporta como variable de entorno:
- printenv | grep NEW_VAR
OutputNEW_VAR=Testing export
Ahora, salgamos de nuevo a nuestro shell original:
- exit
Veamos si nuestra nueva variable está disponible:
- echo $NEW_VAR
No se devuelve nada.
Esto se debe a que las variables de entorno sólo se pasan a los procesos hijos. No hay una forma incorporada de establecer las variables de entorno del shell padre. Esto es bueno en la mayoría de los casos y evita que los programas afecten al entorno operativo desde el que fueron llamados.
La variable NEW_VAR
se estableció como una variable de entorno en nuestro shell hijo. Esta variable estaría disponible para sí misma y para cualquiera de sus shells y procesos hijos. Cuando salimos de nuevo a nuestro shell principal, ese entorno fue destruido.
Demoting and Unsetting Variables
Aún tenemos nuestra variable TEST_VAR
definida como una variable de entorno. Podemos volver a convertirla en una variable de shell escribiendo:
- export -n TEST_VAR
Ya no es una variable de entorno:
- printenv | grep TEST_VAR
Sin embargo, sigue siendo una variable de shell:
- set | grep TEST_VAR
OutputTEST_VAR='Hello World!'
Si queremos deshacer completamente una variable, ya sea de shell o ambiental, podemos hacerlo con el comando unset
:
- unset TEST_VAR
Podemos comprobar que ya no está establecida:
- echo $TEST_VAR
No se devuelve nada porque la variable ha sido desestablecida.
Configuración de variables de entorno en el inicio de sesión
Ya hemos mencionado que muchos programas utilizan variables de entorno para decidir las particularidades de su funcionamiento. No queremos tener que configurar variables importantes cada vez que iniciamos una nueva sesión de shell, y ya hemos visto cómo muchas variables ya están configuradas al iniciar la sesión, así que ¿cómo hacemos y definimos las variables de forma automática?
En realidad, este es un problema más complejo de lo que parece en un principio, debido a los numerosos archivos de configuración que lee el shell bash dependiendo de cómo se inicie.
La diferencia entre sesiones de shell de inicio de sesión, de no inicio de sesión, interactivas y no interactivas
El shell bash lee diferentes archivos de configuración dependiendo de cómo se inicie la sesión.
Una distinción entre las diferentes sesiones es si el shell se está generando como una sesión de inicio de sesión o de no inicio de sesión.
Un shell de inicio de sesión es una sesión de shell que comienza autenticando al usuario. Si está iniciando una sesión de terminal o a través de SSH y se autentifica, su sesión de shell se establecerá como una shell de inicio de sesión.
Si inicia una nueva sesión de shell desde su sesión autenticada, como hicimos llamando al comando bash
desde la terminal, se inicia una sesión de shell de no inicio de sesión. No se le pidieron sus detalles de autenticación cuando inició su shell hijo.
Otra distinción que se puede hacer es si una sesión de shell es interactiva, o no interactiva.
Una sesión de shell interactiva es una sesión de shell que se adjunta a un terminal. Una sesión de shell no interactiva es aquella que no está unida a una sesión de terminal.
Así que cada sesión de shell se clasifica como de inicio de sesión o de no inicio de sesión y como interactiva o no interactiva.
Una sesión normal que comienza con SSH suele ser una shell de inicio de sesión interactiva. Un script ejecutado desde la línea de comandos suele ejecutarse en un shell no interactivo, de no inicio de sesión. Una sesión de terminal puede ser cualquier combinación de estas dos propiedades.
El hecho de que una sesión de shell se clasifique como shell de inicio de sesión o de no inicio de sesión tiene implicaciones en los archivos que se leen para inicializar la sesión de shell.
Una sesión iniciada como sesión de inicio de sesión leerá primero los detalles de configuración del archivo /etc/profile
. A continuación, buscará el primer archivo de configuración del shell de inicio de sesión en el directorio principal del usuario para obtener los detalles de configuración específicos del usuario.
Lee el primer archivo que pueda encontrar de ~/.bash_profile
~/.bash_login
, y ~/.profile
y no lee ningún otro archivo.
En cambio, una sesión definida como un shell sin inicio de sesión leerá /etc/bash.bashrc
y luego el archivo específico del usuario ~/.bashrc
para construir su entorno.
Los shells no interactivos leen la variable de entorno llamada BASH_ENV
y leen el archivo especificado para definir el nuevo entorno.
Implementación de variables de entorno
Como puedes ver, hay una variedad de archivos diferentes que normalmente necesitaríamos mirar para colocar nuestra configuración.
Esto proporciona mucha flexibilidad que puede ayudar en situaciones específicas en las que queremos ciertas configuraciones en un shell de inicio de sesión, y otras configuraciones en un shell de no inicio de sesión. Sin embargo, la mayoría de las veces querremos las mismas configuraciones en ambas situaciones.
Afortunadamente, la mayoría de las distribuciones de Linux configuran los archivos de configuración de inicio de sesión para que sean el origen de los archivos de configuración de no inicio de sesión. Esto significa que puedes definir las variables de entorno que quieras en ambos dentro de los archivos de configuración de no inicio de sesión. Entonces se leerán en ambos escenarios.
Por lo general, estaremos configurando variables de entorno específicas del usuario, y normalmente querremos que nuestras configuraciones estén disponibles tanto en los shells de inicio de sesión como en los de no inicio de sesión. Esto significa que el lugar para definir estas variables es en el archivo ~/.bashrc
.
Abre este archivo ahora:
- nano ~/.bashrc
Es probable que ya contenga bastantes datos. La mayoría de las definiciones aquí son para establecer opciones de bash, que no están relacionadas con las variables de entorno. Puedes establecer variables de entorno como lo harías desde la línea de comandos:
- export VARNAME=value
Cualquier nueva variable de entorno puede ser añadida en cualquier parte del archivo ~/.bashrc
, siempre y cuando no se coloque en medio de otro comando o bucle for. A continuación, podemos guardar y cerrar el archivo. La próxima vez que inicie una sesión de shell, su declaración de variables de entorno se leerá y se pasará al entorno del shell. Puedes forzar tu sesión actual a leer el archivo ahora escribiendo:
- source ~/.bashrc
Conclusión
Las variables de entorno y de la shell están siempre presentes en tus sesiones de la shell y pueden ser muy útiles. Son una forma interesante para que un proceso padre establezca detalles de configuración para sus hijos, y son una forma de establecer opciones fuera de los archivos.
Esto tiene muchas ventajas en situaciones específicas. Por ejemplo, algunos mecanismos de despliegue se basan en variables de entorno para configurar la información de autenticación. Esto es útil porque no requiere mantenerlas en archivos que pueden ser vistos por partes externas.
Hay un montón de otros escenarios más mundanos, pero más comunes, en los que necesitará leer o alterar el entorno de su sistema. Estas herramientas y técnicas deben darle una buena base para hacer estos cambios y utilizarlos correctamente.