Skip to content

Variables de entorno y PATH

💡 Guía de aprendizaje: Cada vez que escribes git o python en la terminal, el sistema tiene que buscar dónde está ese programa. Cada vez que tu código llama a la API de un modelo grande de lenguaje, el programa necesita saber qué clave usar. Ambas cosas dependen del mismo mecanismo: las variables de entorno.


0. Cada programa tiene su propio conjunto de configuración

Cada programa en ejecución tiene un conjunto de configuraciones «clave=valor» llamadas variables de entorno. El programa puede leer estas configuraciones en cualquier momento para conocer su entorno de ejecución.

Haz clic en cualquier variable de la lista de abajo para "ver" su valor en la terminal:

Environment Variable BrowserClick any variable row to inspect its value and purpose in the terminal
VariableExample value
HOME/Users/alice
USERalice
SHELL/bin/zsh
PATH/usr/local/bin:/usr/bin:/bin
PWD/Users/alice/projects
LANGen_US.UTF-8
NODE_ENVdevelopment
OPENAI_API_KEYsk-••••••••••••••••
bash
← Click any variable on the left to inspect it
$
Core concept:Environment variables are key=value configuration owned by each process. A program inherits a copy from its parent process at startup. You can inspect them with echo $VARIABLE and set them with export KEY=value.

1. PATH: Cómo encuentra Shell los comandos que escribes

PATH es una variable de entorno especial que almacena una lista de rutas de directorios (separadas por dos puntos). Cuando escribes git, Shell recorre estos directorios en orden, buscando un archivo ejecutable llamado git — se detiene al encontrar el primero.

bash
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Selecciona un comando y observa el proceso de búsqueda directorio por directorio:

PATH Search ProcessEnter a command name and see how the shell searches directories
Choose command:
Current PATH:
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
/usr/local/bin
Waiting
/usr/bin
Waiting
/bin
Waiting
/usr/sbin
Waiting
/sbin
Waiting
Core mechanism:After the shell receives a command name, it searches directories in PATH order. The first match wins and the search stops. That makes PATH order important: earlier directories have higher priority.

Tres reglas clave:

  • Cuanto más al principio esté un directorio en PATH, mayor será su prioridad
  • Se detiene al encontrar la primera coincidencia, sin continuar la búsqueda
  • Si ningún directorio lo contiene → command not found

2. ¿Por qué hay que reiniciar la terminal después de instalar una herramienta?

Al instalar herramientas como nvm, Homebrew o conda, el script de instalación añade automáticamente una línea en ~/.zshrc para incluir su directorio en PATH:

bash
# Contenido escrito automáticamente por el script de instalación (ejemplo)
export PATH="/usr/local/opt/python@3.12/bin:$PATH"

Esta línea solo se ejecuta cuando se inicia un nuevo Shell. Las ventanas de terminal ya abiertas no se ven afectadas, por lo que:

bash
# Sin reiniciar, también puedes hacerlo efectivo inmediatamente
source ~/.zshrc

Situaciones comunes con herramientas de desarrollo con IA:

bash
# Ollama / pipx instalados pero dan command not found
which ollama          # Ver la ubicación real de instalación

# Ruta de herramientas CLI instaladas con pip (añadir a PATH)
# macOS: ~/Library/Python/3.x/bin
# Linux: ~/.local/bin
export PATH="$PATH:$HOME/.local/bin"

# Se recomienda usar pipx para instalar herramientas CLI, gestiona PATH automáticamente
pipx install aider-chat

3. Ámbito de las variables: ¿Quién puede ver esta variable?

Las variables de entorno no se difunden a todos los programas — cada proceso tiene su propia copia, heredada del proceso padre. Modificar tu propia copia no afecta al proceso padre.

El siguiente diagrama muestra tres niveles. En el «nivel de usuario», exporta una nueva variable y comprueba si aparece en el «nivel de proceso»:

Three Levels of Environment VariablesVariables flow one way from outer scopes to inner scopes; child processes inherit a copy from parents
🖥️
System level /etc/environment
Visible to all users and processes; configured by an administrator
PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
▼ Child process inherits the parent environment
👤
User level ~/.zshrc
Affects only the current user and is loaded when the login shell starts
HOME=/Users/alice
SHELL=/bin/zsh
NVM_DIR=$HOME/.nvm
=
▼ Start a child process, such as node app.js
⚙️
Process level (currently running program)
Inherits variables from upper levels, disappears on exit, and does not modify the parent process
PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
HOME=/Users/alice
SHELL=/bin/zsh
NVM_DIR=$HOME/.nvm
NODE_ENV=development
PORT=3000
One-way flow:Variables are inherited downward only. Changing a variable in a child process does not affect its parent. Variables set with export in a terminal also disappear when that terminal closes.

4. export: Determina si un proceso hijo puede leer esta variable

Al definir una variable, añadir o no export marca una diferencia fundamental:

export Decides Whether Child Processes Can See a VariableToggle the switch and observe whether the child process can read a variable set by the parent
Parent process (Shell)
$MY_VAR="hello"
$echo $MY_VAR
hello
$bash -c 'echo $MY_VAR'
Start child process
Variable not inherited
Child process (bash -c ...)
$echo $MY_VAR
(empty output)
#A child process cannot modify parent variables
Without export: The variable exists only in the current shell, so the child process reads an empty string.

Para que una variable persista entre sesiones, escribe el export en un archivo de configuración:

bash
# macOS (zsh)
echo 'export MY_VAR="value"' >> ~/.zshrc
source ~/.zshrc       # Efectivo inmediatamente, sin reabrir la terminal

# Linux (bash)
echo 'export MY_VAR="value"' >> ~/.bashrc
source ~/.bashrc

5. Claves de API: Nunca las escribas en el código

Al llamar a APIs como OpenAI, Anthropic o DeepSeek, la clave es tu «DNI + tarjeta de crédito». Si se filtra, otros pueden usar tu cuota y tú pagas la factura.

El error más común es escribir la clave directamente en el código:

Hard-coded Keys vs Environment VariablesThe same feature, two implementations, completely different security outcomes
Dangerous: key written in code
# Python
import openai
 
client = openai.OpenAI(
api_key="sk-proj-abc123..."
)
💀After git push, the key is public on GitHub
💀Crawlers can find it quickly and generate costs
💀GitHub Secret Scanner may revoke the key automatically
💀Deleting the commit is not enough because Git history keeps it
Correct: read from environment variable
# Python
import openai, os
 
client = openai.OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
The code contains no secret and can be open-sourced safely
Development, testing, and production can use different keys
If a key leaks, regenerate it without changing code
Team members can use separate keys without affecting each other
Golden rule:A secret string in code means the secret is already leaked. GitHub Secret Scanner can detect prefixes such as sk- shortly after a push and notify providers to revoke them. Even if you delete the commit, Git history still contains it.

6. Desarrollo local: Usa un archivo .env para gestionar las claves

En desarrollo local, coloca las claves en un archivo .env en la raíz del proyecto; el código las lee a través de la librería dotenv. .env debe añadirse a .gitignore y nunca subirse a Git.

Escribe la configuración a la izquierda y léela a la derecha — cambia de lenguaje para ver ambos enfoques:

.env File + Code ReadingConfiguration on the left, code on the right; the variable name is the only link
📄 .env Do not commit
# Local development config, do not commit to Git
OPENAI_API_KEY=sk-proj-abc123...
DATABASE_URL=postgresql://localhost/dev
PORT=3000
NODE_ENV=development
📋 .env.example Can commit
# Copy to .env and fill in real values
OPENAI_API_KEY=(leave empty)
DATABASE_URL=(leave empty)
PORT=(leave empty)
NODE_ENV=(leave empty)
💻 main.py
# pip install python-dotenv openai
from dotenv import load_dotenv
import os, openai
 
load_dotenv() # Read .env file
 
client = openai.OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
 
db = os.environ.get("DATABASE_URL")
port = int(os.environ.get("PORT", 8000))
Values actually read by the program
OPENAI_API_KEYsk-proj-abc123...
DATABASE_URLpostgresql://localhost/dev
PORT3000
Workflow:load_dotenv() / import 'dotenv/config' reads the .env file at startup, injects its key-value pairs into the process environment, and the code reads them with os.environ or process.env. The two sides are connected only by variable names.

7. Entorno de producción: Deja que la plataforma inyecte las claves

.env es una herramienta de conveniencia para la fase de desarrollo. En servidores y plataformas en la nube, el entorno de ejecución debe ser responsable de inyectar las claves; el código en sí no necesita saber dónde se almacenan:

How Production Injects Secrets.env is a development convenience; servers should not rely on it
/etc/systemd/system/myapp.service
# Recommended: use a separate secret file with controlled permissions
[Service]
EnvironmentFile=/etc/myapp/secrets.env
ExecStart=/usr/bin/node /app/index.js
# Set file permissions so only the owner can read it
sudo chmod 600 /etc/myapp/secrets.env
sudo chown deploy:deploy /etc/myapp/secrets.env
# Reload configuration and restart the service
sudo systemctl daemon-reload
sudo systemctl restart myapp
After chmod 600, only the deploy user can read the secret file; other accounts cannot access it
Secrets are separated from code, so rotating a key does not require redeploying code
Avoid writing Environment="KEY=val" directly in the systemd file; it requires reloads and leaves plaintext in config
Principle:.env files are convenient for local development. In production, the runtime platform should inject environment variables, while application code stays unaware of where secrets live or how they arrived.

8. Resolución de problemas práctica

command not found

bash
# Paso 1: Confirmar si está en PATH
which python3         # Si hay salida, lo encontró

# Paso 2: Encontrar la ubicación real del programa (macOS)
brew list python | grep bin

# Paso 3: Añadir el directorio a PATH
export PATH="/ruta/encontrada:$PATH"
source ~/.zshrc       # Recuerda hacer source después de escribir en el archivo de configuración

Tengo dos versiones instaladas y no usa la que quiero

bash
which python
# /usr/bin/python ← Versión antigua del sistema, más arriba en PATH

# Pon el directorio de la nueva versión al principio de PATH
export PATH="/usr/local/bin:$PATH"

which python
# /usr/local/bin/python ← Nueva versión, ahora tiene prioridad

La variable está definida pero el programa no la lee

CausaSolución
Olvidaste exportAñade export y vuelve a probar
Modificaste ~/.zshrc pero no surtió efectosource ~/.zshrc
Usas .env pero no tienes dotenv instaladopip install python-dotenv / npm install dotenv
En el servidor solo funciona en la sesión SSHUsa EnvironmentFile de systemd

Glosario de términos

TérminoSignificado
PATHAlmacena la lista de directorios donde Shell busca ejecutables, separados por dos puntos; el orden determina la prioridad
exportMarca una variable como heredable; los procesos hijos obtienen automáticamente una copia al iniciar
sourceRe-ejecuta un archivo de configuración en el Shell actual, haciendo que los cambios surtan efecto inmediatamente
whichMuestra la ruta del ejecutable correspondiente a un comando (resultado de la búsqueda en PATH)
.envArchivo de configuración local del proyecto, almacena claves de desarrollo; debe añadirse a .gitignore
.env.examplePlantilla con nombres de variables completos y valores vacíos; puede subirse a Git de forma segura
chmod 600Permisos de archivo: solo el propietario puede leer y escribir; adecuado para proteger archivos de claves
Secret ScannerEscaneo automático de fugas de claves en plataformas como GitHub; notifica a los proveedores para su revocación