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 jest widoczna w jednym terminalu, a w innym nie, przyczyną jest często tryb startowy Zsh. Najczęściej sięgamy po ~/.zprofile i ~/.zshrc, ale sama nazwa pliku nie mówi, czy dana linia tam pasuje. Ten artykuł pokazuje, które pliki startowe czyta każdy rodzaj Zsh, co należy do każdego z nich i jakie polecenia mówią, w jakiej powłoce jesteś.
Zsh wybiera pliki startowe na podstawie dwóch niezależnych właściwości: czy powłoka jest powłoką logowania (ang. login shell) i czy jest interaktywna. Aplikacje terminalowe w systemach macOS i Linux mogą wybierać różne kombinacje, dlatego sprawdź uruchomioną powłokę zamiast zakładać, że decyduje o tym system operacyjny.
Powłoka interaktywna służy do wprowadzania poleceń, zwykle z terminala, a -i może wymusić ten tryb. Powłoka logowania uruchamia się w trybie logowania wybranym przez program uruchamiający lub -l; nie oznacza to, że uruchamia się tylko podczas logowania do komputera (opcje stanu powłoki Zsh).
Zsh sprawdza dwie niezależne flagi
Powłoka może być:
- logowania i interaktywna, jak nowe okno Terminala w macOS lub
zsh -l - nielogowania i interaktywna, jak zagnieżdżony
zshwpisany w innej powłoce - logowania i nieinteraktywna, jak
zsh -lc 'command' - nielogowania i nieinteraktywna, jak
zsh -c 'command'
Diagram stawia obie flagi na dwóch osiach. Każda komórka wymienia programy, które zwykle uruchamiają taką powłokę, i zaznacza, które z pięciu plików użytkownika czyta.
Tryb wybiera program, który uruchamia powłokę. Oto domyślne ustawienia popularnych programów:
| Uruchamiane przez | Tryb domyślny |
|---|---|
| macOS Terminal, iTerm2 | logowania, interaktywny |
| GNOME Terminal | nielogowania, interaktywny |
| terminal VS Code w macOS | logowania, interaktywny (zsh -l) |
| terminal VS Code w Linuksie | nielogowania, interaktywny |
ssh host | logowania, interaktywny |
ssh host 'command' | nielogowania, nieinteraktywny |
nowe okno tmux z pustym default-command | logowania, interaktywny |
zsh wpisany w powłoce | nielogowania, interaktywny |
zsh script.zsh | nielogowania, nieinteraktywny |
Twoje ustawienia mogą zmienić każdy wiersz. Aby zobaczyć rzeczywisty tryb bieżącej powłoki, uruchom:
print -r -- "interactive=$options[interactive] login=$options[login]"
Rzeczywista kolejność startu
Przy domyślnych opcjach startowych Zsh czyta pliki globalne, a potem odpowiadający im plik użytkownika. Kolejność plików użytkownika jest taka:
$ZDOTDIR/.zshenvprzy każdym uruchomieniu Zsh$ZDOTDIR/.zprofile, jeśli powłoka jest powłoką logowania$ZDOTDIR/.zshrc, jeśli powłoka jest interaktywna$ZDOTDIR/.zlogin, jeśli powłoka jest powłoką logowania$ZDOTDIR/.zlogout, gdy interaktywna powłoka logowania kończy się normalnie
Jeśli ZDOTDIR nie jest ustawiony, Zsh używa $HOME. Położenie plików systemowych zależy od instalacji; typowe domyślne to /etc/zshenv, /etc/zprofile, /etc/zshrc, /etc/zlogin i /etc/zlogout (podręcznik Zsh).
W macOS /etc/zprofile uruchamia path_helper, który umieszcza katalogi systemowe na początku PATH. Własne wpisy PATH ustawiaj w ~/.zprofile, który działa później, a nie w ~/.zshenv.
RCS to domyślnie włączona opcja Zsh, która pozwala czytać pliki startowe po /etc/zshenv. zsh -f ją wyłącza i zwykle pomija pozostałe pliki startowe. /etc/zshenv nadal się wykonuje i może ponownie włączyć RCS. Jeśli problem tam znika, sprawdź pominiętą konfigurację startową (podręcznik Zsh).
Następny diagram pokazuje pełną kolejność dla nowego okna Terminala w macOS, razem z plikami globalnymi, oraz to, co dzieje się z wpisem PATH dodanym w ~/.zshenv w porównaniu z ~/.zprofile.
.zprofile działa raz na proces powłoki logowania, a nie raz na logowanie do komputera. Jeśli każda nowa karta terminala uruchamia powłokę logowania, każda karta czyta ten plik.
Co należy do którego pliku
| Plik | Reguła wyboru | Co pasuje | Unikaj |
|---|---|---|---|
.zshenv | Każdy Zsh | ZDOTDIR i rzadkie zmienne potrzebne każdemu procesowi Zsh | wyjścia, aliasów, ustawień prompt, wywołań sieciowych, wolnych poleceń |
.zprofile | Powłoki logowania | ustawienie ścieżek sesji logowania i eksportowane wartości domyślne | interaktywnych hooków, uzupełniania, przypisań klawiszy |
.zshrc | Powłoki interaktywne | prompt, uzupełnianie, aliasy, opcje powłoki, interaktywne hooki narzędzi | wyjścia lub zmian przeznaczonych dla skryptów |
.zlogin | Powłoki logowania, po .zshrc | rzadkie akcje logowania, które muszą działać po .zshrc | konfiguracji, która musi poprzedzać .zshrc |
.zlogout | Zakończenie powłoki logowania | drobne czyszczenie lub reset terminala | ważnego stanu, który musi przetrwać awarię lub exec |
Nie rozbudowuj .zshenv i nie wypisuj w nim danych
Każde nieinteraktywne zsh -c czyta .zshenv (podręcznik Zsh). echo, wywołanie menedżera pakietów albo kosztowny podproces w tym pliku mogą zepsuć wyjście poleceń i spowolnić skrypty. Większość użytkowników potrzebuje w nim niewiele albo nic.
Typowym wyjątkiem jest ZDOTDIR. Ustaw go w ~/.zshenv, aby trzymać pozostałe pliki startowe w innym katalogu, na przykład ~/.config/zsh.
Używaj .zprofile do konfiguracji tylko dla logowania
Zmienną wyeksportowaną w .zprofile dziedziczą procesy potomne tej powłoki logowania. Nie jest ona automatycznie wstrzykiwana do niezwiązanych aplikacji graficznych, usług ani powłok, których proces nadrzędny nigdy nie czytał tego pliku.
Mały profil w macOS może wczytać Homebrew, ustawić eksportowane wartości domyślne i zbudować PATH bez duplikatów:
# ~/.zprofile
# The Homebrew installer recommends this line on Apple silicon.
eval "$(/opt/homebrew/bin/brew shellenv zsh)"
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 zachowuje każdy wpis tylko raz. Bez niego każde source tego pliku lub zagnieżdżona powłoka logowania dodaje ten sam katalog ponownie, a echo $PATH pokazuje go kilka razy.
Używaj .zshrc do stanu interaktywnego
Nowo uruchomiony zsh dziedziczy wyeksportowane zmienne. Nie dziedziczy aliasów, funkcji, opcji powłoki, przypisań klawiszy ani hooków powłoki nadrzędnej. Każda powłoka interaktywna musi zdefiniować je od nowa, i to robi .zshrc. Zsh pomija .zshrc przy zwykłych uruchomieniach nieinteraktywnych.
Diagram porównuje zagnieżdżony zsh i powłokę skryptu zsh -c uruchomione z tej samej powłoki logowania. W tym przykładzie tylko .zshrc definiuje pokazany stan powłoki.
Minimalny .zshrc ustawia opcje, uzupełnianie, aliasy i przypisania klawiszy:
# ~/.zshrc
setopt auto_cd hist_ignore_all_dups share_history
autoload -Uz compinit
compinit
alias ll='ls -lah'
bindkey -e
Gdzie trafiają hooki menedżerów wersji
Rada „umieść menedżery wersji w .zprofile, bo są wolne” jest zawodna. Menedżer wersji może generować kilka rodzajów kodu:
- statyczną ścieżkę lub zmienną katalogu głównego
- ścieżkę shimów poleceń potrzebną procesom potomnym
- definicje uzupełniania
- funkcje powłoki, które zmieniają bieżącą powłokę
- hooki zmiany katalogu do automatycznego przełączania wersji
Dwa pierwsze są eksportowane i trafiają do powłok potomnych. Reszta to stan powłoki, więc musi istnieć w każdej powłoce interaktywnej, także w zagnieżdżonym zsh uruchomionym z edytora. Dlatego obecna konfiguracja fnm dla Zsh umieszcza ten hook w .zshrc:
eval "$(fnm env --use-on-cd --shell zsh)"
Obecna 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 do ustawiania ścieżki shimów, a pełne pyenv init instaluje też uzupełnianie i funkcje powłoki. Zanim rozdzielisz konfigurację narzędzia, sprawdź jego aktualną dokumentację i wygenerowany kod.
Jeśli start jest wolny, zmierz go, zanim przeniesiesz kod do trybu, w którym przestaje działać. Sekcja o diagnozie pokazuje, jak.
Nie wczytuj całego profilu z .zshrc
Częste obejście między platformami wygląda tak:
# Avoid this blanket coupling.
source ~/.zprofile
To zamienia akcje tylko dla logowania w akcje przy każdej powłoce interaktywnej. Może ponownie uruchomić ssh-agent, ponownie poprosić o dostęp do pęku kluczy, wypisać dane albo dodać wpisy PATH dwa razy.
Jeśli zarówno powłoki logowania, jak i interaktywne powłoki nielogowania potrzebują małego zestawu statycznych eksportów, wydziel idempotentny fragment i wczytaj go świadomie:
# ~/.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.
Powłoka logowania czyta environment.zsh przez .zprofile. Interaktywna powłoka nielogowania czyta go przez .zshrc. Działania logowania, takie jak ssh-agent, zostają w .zprofile, więc ten wzorzec oddziela wspólne dane od skutków ubocznych logowania. Inna możliwość to ustawić terminal tak, by uruchamiał powłokę logowania; wtedy każda karta czyta .zprofile.
Diagnozuj powłokę, która jest wolna lub nie ma stanu
Zacznij od objawu: wolna powłoka albo brakujące ustawienie.
Odtwórz każdy tryb bezpośrednio:
zsh -lic 'print "login interactive"'
zsh -ic 'print "non-login interactive"'
zsh -lc 'print "login non-interactive"'
zsh -c 'print "non-login non-interactive"'
Przy wolnej powłoce użyj time do czasu całkowitego, zprof, by zobaczyć, która funkcja zajmuje czas, i śladu -x, by zobaczyć, który plik i która linia się wykonują.
Zmierz tryb, który uruchamia twój terminal:
time zsh -lic exit
time zsh -ic exit
Wczytaj profiler na początku .zshrc i wypisz jego raport na końcu. Następna nowa powłoka wypisze tabelę funkcji posortowaną według czasu:
# first line of ~/.zshrc
zmodload zsh/zprof
# last line of ~/.zshrc
zprof
Gdy źródło jest niejasne, prześledź wykonanie plików i linii:
PS4='%N:%i> ' zsh -xlic exit
Uruchom ślad na czystym koncie testowym albo przejrzyj go przed udostępnieniem: polecenia startowe mogą rozwijać wartości typu token i inne wrażliwe wartości.
Przy brakującym pliku wykonywalnym sprawdź tryb i ścieżkę:
print -r -- "interactive=$options[interactive] login=$options[login]"
print -l -- $path
whence -va python node uv
Aby zastosować zmianę, otwórz nową kartę albo uruchom exec zsh -l (logowania) lub exec zsh (nielogowania). source ~/.zshrc uruchamia plik ponownie w bieżącej powłoce i zachowuje wszystko, co ustawiła stara wersja.
Podsumowanie
Przydatne rozróżnienie to nie „środowisko kontra aliasy”. Chodzi o stan tylko dla logowania kontra stan interaktywny oraz niewielką część, która musi działać w każdym procesie Zsh.
Gdy powłoka zachowuje się źle, uruchom polecenie print z pierwszej sekcji, a potem sprawdź, czy ustawienie leży w pliku, który ten tryb czyta.