Archivos de inicio de Zsh: .zprofile frente a .zshrc en macOS y Linux
Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.
Si el terminal va lento o una variable de entorno aparece en un terminal pero no en otro, la causa suele estar en el modo de inicio de Zsh. Los dos archivos que más se suelen utilizar son ~/.zprofile y ~/.zshrc, pero el nombre del archivo, por sí solo, no indica dónde debe ir cada línea.
Zsh selecciona los archivos de inicio a partir de dos propiedades independientes: si el shell es un login shell y si es interactivo. Las aplicaciones de terminal de macOS y Linux pueden elegir combinaciones distintas, así que debes inspeccionar el shell en ejecución en lugar de asumir que lo decide el sistema operativo.
TL;DR. Pon la inicialización de la sesión de login en
.zprofiley el comportamiento interactivo en.zshrc. Mantén.zshenvsilencioso y minimalista cuandoRCSesté definido. No muevas los hooks interactivos del gestor de versiones a.zprofileni cargues el perfil completo desde.zshrc; inspecciona el código generado por la herramienta y sigue sus instrucciones actuales para Zsh.
Zsh evalúa dos flags independientes
Un shell puede ser:
- login e interactivo, cuando Apple Terminal está configurado para abrir el shell de login predeterminado de la cuenta
- no-login e interactivo, como un
zshanidado o como sucede en muchas configuraciones de terminal de Linux - login y no interactivo, como
zsh -lc 'command' - no-login y no interactivo, como
zsh -c 'command'
Las aplicaciones de terminal, los IDE, las sesiones remotas, los multiplexores y los flags explícitos del shell pueden elegir modos distintos, por lo que el sistema operativo, por sí solo, no determina el resultado.
Pregúntaselo al shell en ejecución en lugar de hacer suposiciones:
print -r -- "interactive=$options[interactive] login=$options[login]"
El orden de inicio real
Zsh lee los archivos globales y después el archivo de usuario correspondiente. Con las opciones predeterminadas de RCS, el orden de los archivos de usuario es:
$ZDOTDIR/.zshenven cada invocación de Zsh$ZDOTDIR/.zprofilesi el shell es un login shell$ZDOTDIR/.zshrcsi el shell es interactivo$ZDOTDIR/.zloginsi el shell es un login shell$ZDOTDIR/.zlogoutcuando un login shell termina con normalidad
Si ZDOTDIR no está definido, Zsh utiliza $HOME. Las ubicaciones de los archivos de todo el sistema dependen de la instalación; los valores predeterminados habituales son /etc/zshenv, /etc/zprofile, /etc/zshrc, /etc/zlogin y /etc/zlogout (manual de Zsh).
zsh -f comienza con RCS sin definir, por lo que normalmente omite los archivos de usuario $ZDOTDIR anteriores; /etc/zshenv siempre se lee y puede modificar esa opción.
.zprofile se ejecuta una vez por cada proceso de login shell, no una vez por cada inicio de sesión en el equipo. Si cada pestaña nueva del terminal inicia un login shell, todas las pestañas lo leen.
Qué corresponde a cada archivo
| Archivo | Criterio de selección | Buenos candidatos | Evitar |
|---|---|---|---|
.zshenv | Cada Zsh con RCS establecido | Variables poco frecuentes necesarias para todos los procesos de Zsh | salida, alias, prompts, llamadas de red, comandos lentos |
.zprofile | Shells de inicio de sesión | configuración de rutas de la sesión de inicio de sesión y valores predeterminados exportados | hooks interactivos, completado, combinaciones de teclas |
.zshrc | Shells interactivos | prompt, completado, alias, opciones del shell, hooks de herramientas interactivas | salida o mutaciones destinadas a scripts |
.zlogin | Shells de inicio de sesión, después de .zshrc | acciones poco frecuentes posteriores al inicio de sesión interactivo | configuración que debe preceder a .zshrc |
.zlogout | Salida de un shell de inicio de sesión | pequeñas acciones de limpieza o restablecimiento del terminal | estado importante que debe sobrevivir a fallos o a exec |
Mantén .zshenv sin complicaciones cuando RCS esté establecido
Con RCS establecido, cada zsh -c no interactivo lee .zshenv (manual de Zsh). Un echo, una llamada al gestor de paquetes o un subproceso costoso ahí pueden corromper la salida de los comandos y ralentizar los scripts. La mayoría de los usuarios necesitan poco o nada en este archivo.
Una variable exportada en .zprofile se hereda en los procesos hijos de ese shell de inicio de sesión. No se inyecta automáticamente en aplicaciones gráficas, servicios o shells independientes cuyo proceso padre nunca haya leído el archivo.
Usa .zprofile para la configuración exclusiva del inicio de sesión
Un perfil pequeño podría establecer valores predeterminados exportados y una ruta idempotente:
# ~/.zprofile
export EDITOR=nvim
export VISUAL=nvim
# Zsh ties the path array to the PATH scalar.
typeset -U path PATH
path=("$HOME/.local/bin" $path)
export PATH
typeset -U elimina las entradas duplicadas de un array. Esto hace más seguro cargar el archivo varias veces, aunque los archivos de inicio deberían seguir evitando trabajo innecesario.
Usa .zshrc para el estado interactivo
# ~/.zshrc
setopt auto_cd hist_ignore_all_dups share_history
autoload -Uz compinit
compinit
alias ll='ls -lah'
bindkey -e
Los alias, widgets de completado, mapas de teclas, prompts y hooks de cambio de directorio pertenecen al shell interactivo que los utiliza.
Los gestores de versiones traspasan los límites de la división sencilla por archivos
«Pon los gestores de versiones en .zprofile porque son lentos» es un consejo poco fiable. Un gestor de versiones puede emitir varios tipos de código:
- una ruta estática o una variable raíz
- la ruta a un command shim que necesitan los procesos hijos
- definiciones de completado
- funciones del shell que cambian el shell actual
- hooks de cambio de directorio para cambiar automáticamente de versión
Las partes interactivas deben existir en todos los shells interactivos, incluido un zsh anidado iniciado desde un editor. Por eso, la configuración actual de fnm para Zsh coloca este hook en .zshrc:
eval "$(fnm env --use-on-cd --shell zsh)"
La configuración actual de pyenv para Zsh también incluye una inicialización interactiva completa en .zshrc:
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && path=("$PYENV_ROOT/bin" $path)
eval "$(pyenv init - zsh)"
La documentación de pyenv describe un modo pyenv init --path más limitado para configurar la ruta de los shims, mientras que pyenv init también instala el autocompletado y las funciones del shell. Consulta la documentación actual y la salida generada por cada herramienta antes de dividir su configuración.
Si el arranque es lento, mídelo antes de trasladar código a un modo en el que deje de funcionar.
No cargues el perfil completo desde .zshrc
Una solución habitual para distintas plataformas es:
# Avoid this blanket coupling.
source ~/.zprofile
Esto convierte las acciones exclusivas del login en acciones que se ejecutan en cada shell interactivo, y puede repetir el arranque del agente, el acceso al llavero, la salida por pantalla o la modificación de la ruta.
Si tanto los shells interactivos de login como los que no lo son necesitan un pequeño conjunto de exports estáticos, extrae un fragmento idempotente y cárgalo de forma explícita:
# ~/.config/zsh/environment.zsh
typeset -U path PATH
path=("$HOME/.local/bin" $path)
export PATH EDITOR=nvim VISUAL=nvim
# ~/.zprofile
source "$HOME/.config/zsh/environment.zsh"
# ~/.zshrc
if [[ ! -o login ]]; then
source "$HOME/.config/zsh/environment.zsh"
fi
# Interactive-only configuration follows.
Este patrón mantiene separados los datos compartidos y los efectos secundarios exclusivos del login. Otra opción válida es configurar de forma coherente el terminal o el gestor de sesiones, en lugar de admitir ambos modos.
Diagnostica el shell que es lento o carece de estado
Reproduce cada modo directamente:
zsh -lic 'print "login interactive"'
zsh -ic 'print "non-login interactive"'
zsh -lc 'print "login non-interactive"'
zsh -c 'print "non-login non-interactive"'
Mide el modo que los usuarios ejecutan realmente:
time zsh -lic exit
time zsh -ic exit
Traza la ejecución de archivos y líneas cuando no esté claro qué se carga:
PS4='%N:%i> ' zsh -xlic exit
Ejecuta la traza en una cuenta de prueba limpia o revísala antes de compartirla: los comandos de arranque pueden expandir tokens y otros valores sensibles.
Si falta un ejecutable, inspecciona tanto el modo como la ruta:
print -r -- "interactive=$options[interactive] login=$options[login]"
print -l -- $path
whence -va python node uv
Conclusión
La distinción útil no es «entorno frente a alias». Es el estado exclusivo del login frente al estado interactivo, además de la pequeña cantidad de configuración que debe afectar a todos los procesos de Zsh cuando está definido RCS.
Confirma los flags del shell, mantén silenciosos los archivos de arranque y coloca cada hook generado donde estén disponibles todas las funciones que necesita. Así, la configuración será portable entre aplicaciones de terminal, sin asumir que macOS y Linux tienen un único modo fijo de lanzamiento.