Pliki startowe Zsh: .zprofile a .zshrc w systemach macOS i Linux

Tłumaczenie automatyczne Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.

Jeśli terminal działa wolno albo zmienna środowiskowa pojawia się w jednym terminalu, ale nie w innym, przyczyną często jest tryb uruchamiania Zsh. Dwa pliki, po które najczęściej sięgamy, to ~/.zprofile i ~/.zshrc, ale sama nazwa pliku nie mówi jeszcze, czy dana linia powinna się w nim znaleźć.

Zsh wybiera pliki startowe na podstawie dwóch niezależnych właściwości: tego, czy powłoka jest powłoką logowania, oraz tego, czy jest interaktywna. Aplikacje terminalowe w systemach macOS i Linux mogą wybierać różne kombinacje, dlatego zamiast zakładać, że decyduje o tym system operacyjny, sprawdź uruchomioną powłokę.

W skrócie. Umieść inicjalizację sesji logowania w .zprofile, a zachowanie interaktywne w .zshrc. Zachowaj .zshenv w stanie cichym i minimalistycznym, gdy ustawiona jest RCS. Nie przenoś interaktywnych hooków menedżerów wersji do .zprofile ani nie wczytuj całego profilu z .zshrc; sprawdź kod generowany przez dane narzędzie i postępuj zgodnie z jego aktualnymi instrukcjami dotyczącymi Zsh.

Zsh ocenia dwie niezależne flagi

Pliki startowe Zsh wybierane na podstawie trybu logowania i interaktywnościPliki startowe Zsh wybierane na podstawie trybu logowania i interaktywności

Powłoka może być:

  • logowania i interaktywna, gdy Apple Terminal jest skonfigurowany tak, aby uruchamiać domyślną powłokę logowania konta
  • niebędąca powłoką logowania, ale interaktywna, jak zagnieżdżona zsh lub w wielu konfiguracjach terminali w systemie Linux
  • logowania i nieinteraktywna, jak zsh -lc 'command'
  • niebędąca powłoką logowania i nieinteraktywna, jak zsh -c 'command'

Aplikacje terminalowe, IDE, sesje zdalne, multipleksery i jawne flagi powłoki mogą wybierać różne tryby, dlatego sam system operacyjny nie określa wyniku.

Zapytaj uruchomioną powłokę, zamiast zgadywać:

print -r -- "interactive=$options[interactive] login=$options[login]"

Rzeczywista kolejność plików startowych

Zsh wczytuje pliki globalne, a następnie odpowiedni plik użytkownika. Przy domyślnych opcjach RCS kolejność plików użytkownika jest następująca:

  1. $ZDOTDIR/.zshenv przy każdym uruchomieniu Zsh
  2. $ZDOTDIR/.zprofile, jeśli powłoka jest powłoką logowania
  3. $ZDOTDIR/.zshrc, jeśli powłoka jest interaktywna
  4. $ZDOTDIR/.zlogin, jeśli powłoka jest powłoką logowania
  5. $ZDOTDIR/.zlogout przy normalnym zakończeniu powłoki logowania

Jeśli ZDOTDIR nie jest ustawiona, Zsh używa $HOME. Lokalizacje plików systemowych zależą od instalacji; typowe wartości domyślne to /etc/zshenv, /etc/zprofile, /etc/zshrc, /etc/zlogin i /etc/zlogout (podręcznik Zsh).

zsh -f rozpoczyna działanie z wyłączoną RCS, więc zwykle pomija wymienione wyżej pliki użytkownika $ZDOTDIR; /etc/zshenv jest zawsze wczytywany i może zmienić tę opcję.

Sekwencja uruchamiania Zsh dla czterech trybów powłokiSekwencja uruchamiania Zsh dla czterech trybów powłoki

.zprofile jest wykonywany raz dla każdego procesu powłoki logowania, a nie raz na logowanie do komputera. Jeśli każda nowa karta terminala uruchamia powłokę logowania, każda karta go wczyta.

Co powinno znajdować się w każdym pliku

PlikReguła wyboruDobry wybórCzego unikać
.zshenvKażdy Zsh z ustawioną RCSRzadko używane zmienne wymagane przez każdy proces Zshwyjście, aliasy, prompty, wywołania sieciowe, wolne polecenia
.zprofilePowłoki logowaniakonfiguracja ścieżki sesji logowania i eksportowane wartości domyślnehooki interaktywne, uzupełnianie, mapowania klawiszy
.zshrcPowłoki interaktywneprompt, uzupełnianie, aliasy, opcje powłoki, interaktywne hooki narzędziwyjście lub modyfikacje przeznaczone dla skryptów
.zloginPowłoki logowania, po .zshrcrzadkie działania wykonywane po interaktywnej sesji logowaniakonfiguracja, która musi poprzedzać .zshrc
.zlogoutZakończenie powłoki logowanianiewielkie działania czyszczące lub reset terminalaważny stan, który musi przetrwać awarię lub exec

Zachowaj .zshenv w prostym stanie, gdy ustawiona jest RCS

Gdy ustawiona jest RCS, każda nieinteraktywna zsh -c wczytuje .zshenv (podręcznik Zsh). echo, wywołanie menedżera pakietów lub kosztowny podproces w tym miejscu może uszkodzić wyjście poleceń i spowolnić skrypty. Większość użytkowników potrzebuje w tym pliku niewiele albo niczego.

Zmienna eksportowana w .zprofile jest dziedziczona przez procesy potomne tej powłoki logowania. Nie jest automatycznie wstrzykiwana do niezależnych aplikacji GUI, usług ani powłok, których proces nadrzędny nie wczytał tego pliku.

Użyj .zprofile do konfiguracji wyłącznie dla sesji logowania

Niewielki profil może ustawić eksportowane wartości domyślne i idempotentną ścieżkę:

# ~/.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 usuwa zduplikowane elementy tablicy. Dzięki temu wielokrotne wczytywanie jest bezpieczniejsze, choć pliki startowe nadal powinny unikać zbędnej pracy.

Użyj .zshrc do konfiguracji stanu interaktywnego

# ~/.zshrc
setopt auto_cd hist_ignore_all_dups share_history

autoload -Uz compinit
compinit

alias ll='ls -lah'
bindkey -e

Aliasy, widgety uzupełniania, mapowania klawiszy, prompty i hooki zmiany katalogu należą do interaktywnej powłoki, która z nich korzysta.

Menedżery wersji wykraczają poza prosty podział plików

Rada „umieść menedżery wersji w .zprofile, bo działają wolno” jest zawodna. Menedżer wersji może generować kilka rodzajów kodu:

  • statyczną ścieżkę lub zmienną root
  • ścieżkę do command shim potrzebną procesom potomnym
  • definicje uzupełniania
  • funkcje powłoki zmieniające bieżącą powłokę
  • hooki zmiany katalogu służące do automatycznego przełączania wersji

Części interaktywne muszą istnieć w każdej interaktywnej powłoce, w tym w zagnieżdżonej zsh uruchomionej z edytora. Dlatego aktualna konfiguracja fnm dla Zsh umieszcza ten hook w .zshrc:

eval "$(fnm env --use-on-cd --shell zsh)"

Aktualna konfiguracja pyenv dla Zsh również umieszcza pełną inicjalizację interaktywną w .zshrc:

export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && path=("$PYENV_ROOT/bin" $path)
eval "$(pyenv init - zsh)"

Dokumentacja Pyenv opisuje węższy tryb pyenv init --path służący do konfiguracji ścieżki shimów, natomiast pełne pyenv init instaluje również uzupełnianie i funkcje powłoki. Zanim rozdzielisz konfigurację, sprawdź aktualną dokumentację narzędzia i generowane przez nie dane wyjściowe.

Jeśli uruchamianie jest wolne, najpierw zmierz jego czas, a dopiero potem przenoś kod do trybu, w którym przestanie działać.

Nie wczytuj całego profilu z .zshrc

Często spotykane obejście problemów między platformami wygląda tak:

# Avoid this blanket coupling.
source ~/.zprofile

Zmienia ono działania wykonywane wyłącznie podczas logowania w działania wykonywane przy każdej interaktywnej powłoce i może powtarzać uruchamianie agenta, dostęp do keychaina, wyjście lub modyfikowanie ścieżki.

Jeśli zarówno interaktywne powłoki logowania, jak i powłoki niebędące powłokami logowania potrzebują niewielkiego zestawu statycznych eksportów, wyodrębnij idempotentny fragment i wczytuj go jawnie:

# ~/.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.

Ten wzorzec oddziela współdzielone dane od efektów ubocznych logowania. Inną poprawną opcją jest spójne skonfigurowanie terminala lub menedżera sesji zamiast obsługiwania obu trybów.

Diagnozowanie powolnej powłoki lub brakującego stanu

Odtwórz bezpośrednio każdy tryb:

zsh -lic 'print "login interactive"'
zsh -ic  'print "non-login interactive"'
zsh -lc  'print "login non-interactive"'
zsh -c   'print "non-login non-interactive"'

Zmierz tryb faktycznie uruchamiany przez użytkowników:

time zsh -lic exit
time zsh -ic exit

Śledź wykonywanie plików i poszczególnych linii, gdy źródło problemu nie jest jasne:

PS4='%N:%i> ' zsh -xlic exit

Uruchom śledzenie na czystym koncie testowym albo sprawdź je przed udostępnieniem: polecenia startowe mogą rozwinąć tokeny i inne poufne wartości.

W przypadku brakującego pliku wykonywalnego sprawdź zarówno tryb, jak i ścieżkę:

print -r -- "interactive=$options[interactive] login=$options[login]"
print -l -- $path
whence -va python node uv

Podsumowanie

Najważniejsze rozróżnienie nie przebiega między „środowiskiem a aliasami”. Chodzi o stan wyłącznie dla sesji logowania i stan interaktywny, a także o niewielką część konfiguracji, która musi wpływać na każdy proces Zsh, gdy ustawiona jest RCS.

Potwierdź flagi powłoki, zachowaj ciszę plików startowych i umieść każdy generowany hook w miejscu, w którym dostępne są wszystkie wymagane przez niego funkcje. Dzięki temu konfiguracja będzie przenośna między aplikacjami terminalowymi, bez udawania, że systemy macOS i Linux mają po jednym stałym trybie uruchamiania.

Materiały źródłowe