Ir para o conteúdo

Tradução automática

Este artigo foi traduzido automaticamente a partir da versão original em inglês.

Ficheiros de arranque do Zsh: ~/.zprofile vs ~/.zshrc no macOS e Linux

Se o teu terminal parece lento, ou se as variáveis de ambiente não estão a ser carregadas onde esperas, provavelmente estás a esbarrar na ordem de arranque do Zsh.

A divisão entre ~/.zprofile e ~/.zshrc é uma das fontes de confusão mais comuns quando passas para Zsh, especialmente no macOS, onde os comportamentos por defeito são diferentes do Linux.

TL;DR

~/.zprofile serve para a configuração do ambiente. É executado uma vez por login, o que no macOS significa uma vez por separador do terminal. Coloca aí o teu PATH, EDITOR e gestores de versões como fnm ou pyenv.

~/.zshrc serve para configuração interativa. É executado sempre que inicias uma nova shell. Coloca aí aliases, temas do prompt e key bindings.

Estrutura de configuração do Zsh


O fluxo de arranque da shell

Para saber onde colocar cada coisa, tens de saber quando os ficheiros são carregados. O Zsh tem uma hierarquia específica.

Shells de login vs. interativas

Uma shell de login é a primeira shell que recebes após autenticação. No macOS, cada novo separador ou janela do terminal é, por defeito, uma shell de login. No Linux, abrir um terminal normalmente inicia antes uma shell interativa sem login, e é daí que vem grande parte da confusão entre plataformas.

Uma shell interativa é qualquer shell em que podes escrever comandos.

Eis o que acontece realmente quando abres um terminal no macOS:

Fluxo de arranque do Zsh

A ordem de carregamento

  1. ~/.zshenv (opcional). É executado para todas as shells, incluindo scripts não interativos. Não coloques aqui output nem lógica pesada — pode partir scripts que façam source da tua configuração. Usa-o apenas para variáveis de ambiente que têm mesmo de existir em todo o lado, o que é raro para a maioria das pessoas.
  2. ~/.zprofile. É executado apenas para shells de login. A tua fase de setup.
  3. ~/.zshrc. É executado para shells interativas. A tua fase de personalização.
  4. ~/.zlogin (opcional). É executado no fim do arranque de uma shell de login.

O que vai para onde?

~/.zprofile: a camada de ambiente

É aqui que configuras as coisas que todos os outros processos herdam — paths, variáveis, gestores de versões de linguagens.

O que pertence aqui:

  • Modificações de PATH.
  • Variáveis de ambiente: EDITOR, LANG, GOPATH, JAVA_HOME.
  • Inicialização de ferramentas que mexe no ambiente: pyenv, rbenv, fnm, cargo.

Estas coisas só precisam de ser calculadas uma vez. Se as colocares em .zshrc, são recalculadas sempre que abres uma sub-shell ou executas um script, o que desperdiça tempo e pode deixar entradas duplicadas no teu PATH.

# ~/.zprofile

# 1. Set up your PATH
# Local bin first so your tools override system ones
export PATH="$HOME/.local/bin:/opt/homebrew/bin:$PATH"

# 2. Global variables
export EDITOR="nvim"
export VISUAL="nvim"
export LANG="en_US.UTF-8"

# 3. Version managers (the heavy ones)
# Doing this here keeps shell startup fast
eval "$(fnm env --use-on-cd)"
eval "$(pyenv init -)"

~/.zshrc: a camada interativa

É aqui que personalizas a shell onde realmente escreves comandos.

O que pertence aqui:

  • Aliases: alias g='git'.
  • O teu prompt: Starship, Powerlevel10k, Pure.
  • Compleções: compinit.
  • Key bindings: bindkey.
  • Opções da shell: setopt autocd, setopt histignorealldups.

Estas coisas só importam quando há uma pessoa ao teclado. Um script a correr em background não precisa do teu prompt nem dos teus aliases de git.

# ~/.zshrc

# 1. Prompt
autoload -Uz promptinit && promptinit
prompt pure

# 2. Aliases
alias ll='ls -lah'
alias g='git'
alias gs='git status'

# 3. Shell options
setopt autocd              # cd by typing the directory name
setopt histignorealldups   # skip duplicate history entries
setopt share_history       # share history across tabs

# 4. Completions
autoload -Uz compinit && compinit

Porque não colocar tudo num só ficheiro?

Podes estar a perguntar-te: se .zprofile é executado primeiro, porque não largar aí os teus aliases e ignorar .zshrc por completo?

A resposta resume-se a herança vs. redefinição.

As variáveis de ambiente são herdadas

Quando fazes export EDITOR="vim" numa shell pai, todos os processos filhos a herdam: sub-shells, scripts, programas. Defines uma vez e propaga-se pela árvore de processos, e é por isso que .zprofile é o sítio certo para export.

Aliases e funções não são herdados

Aliases como alias g='git' e funções de shell são locais à shell atual. Não passam para shells filhas.

Se definires um alias em .zprofile, ele existe na tua shell de login de topo. No momento em que escreves zsh para iniciar uma sub-shell, ou executas um script, esse alias desaparece. Para ter aliases em todo o lado, tens de os redefinir em cada nova shell interativa. É exatamente para isso que serve .zshrc.

Os scripts não precisam de funcionalidades para humanos

Quando executas um script de shell (./deploy.sh), ele inicia uma nova shell não interativa. Não precisa do teu prompt, não precisa dos teus aliases de git e certamente não quer ficar à espera que oh-my-zsh acabe de carregar. Manter a configuração interativa em .zshrc garante que os scripts correm de forma rápida e limpa, sem que a tua personalização pessoal se infiltre.


Erros comuns

Colocar nvm ou pyenv em .zshrc

Abres um novo separador de terminal e demora dois ou três segundos até poderes escrever alguma coisa. Os gestores de versões costumam ter uma inicialização pesada, e .zshrc é executado sempre. Move-os para ~/.zprofile e a latência desaparece.

Um PATH que não para de crescer

O teu $PATH acaba com os mesmos diretórios listados cinco vezes. A causa é quase sempre export PATH="$HOME/bin:$PATH" em .zshrc: cada reload (source ~/.zshrc) ou sub-shell volta a acrescentar o path. Move as definições de PATH para ~/.zprofile.

Recarregar depois de alterações

As alterações a ~/.zprofile não se aplicam à tua shell atual, porque .zprofile só é lido no login. Podes fechar o separador e abrir um novo (a opção mais simples) ou executar source ~/.zprofile manualmente.

Para .zshrc, basta:

source ~/.zshrc

Uma configuração que funciona no macOS e Linux

Se alternas entre máquinas (macOS no trabalho, Linux em casa, ou ao contrário), vais encontrar uma nuance. Os terminais em Linux começam muitas vezes como shells sem login, o que significa que ignoram ~/.zprofile por completo.

A solução habitual é fazer source de .zprofile a partir de .zshrc quando ainda não foi carregado:

# ~/.zshrc

# On Linux/non-login shells, make sure the environment is set
if [[ -o interactive && ! -o login ]]; then
    [[ -f ~/.zprofile ]] && source ~/.zprofile
fi

# ... rest of your interactive config

Resumo

File Objetivo Exemplos
~/.zshenv Variáveis de ambiente críticas ZDOTDIR (apenas para utilizadores avançados)
~/.zprofile Configuração do ambiente PATH, EDITOR, eval "$(pyenv init -)"
~/.zshrc Configuração interativa alias, prompt, bindkey, compinit

Duas regras cobrem quase tudo isto. As variáveis são herdadas ao longo da árvore de processos, por isso export pertence em .zprofile. Aliases e funções não são herdados, por isso pertencem em .zshrc e têm de ser redefinidos para cada nova shell interativa. Se os novos separadores parecem lentos, o culpado é quase sempre um pyenv init ou nvm.sh pesado colocado em .zshrc em vez de .zprofile.