Dlaczego powłoki interaktywne w powłokach logowania OSX są domyślnie?

43

W Linuksie i, o ile mi wiadomo, we wszystkich systemach uniksowych emulatory terminali domyślnie uruchamiają interaktywne powłoki bez logowania. Oznacza to, że dla basha uruchomiona powłoka:

Po uruchomieniu interaktywnej powłoki, która nie jest powłoką logowania, bash czyta i wykonuje polecenia z /etc/bash.bashrcoraz ~/.bashrc, jeśli te pliki istnieją. Można temu zapobiec, używając tej --norc opcji.

Opcja --rcfile pliku zmusi bash do odczytu i wykonywania poleceń z pliku zamiast /etc/bash.bashrci ~/.bashrc.

A w przypadku powłok logowania:

Kiedy bash jest wywoływany jako interaktywna powłoka logowania lub jako nieinteraktywna powłoka z --loginopcją, najpierw czyta i wykonuje polecenia z pliku /etc/profile, jeśli plik istnieje. Po przeczytaniu tego pliku, szuka ~/.bash_profile, ~/.bash_logini ~/.profile, w tej kolejności, a odczytuje i wykonuje polecenia z pierwszego, który istnieje i jest czytelny.

--noprofileOpcja może być stosowany, gdy powłoka jest uruchamiany w celu zahamowania tego zachowania.

Na OSX, jednak domyślna powłoka (co jest bash) rozpoczęła się w terminalu domyślnej (Terminal.app) faktycznie źródeł ~/.bash_profilelub ~.profileitd. Innymi słowy, to działa jak powłoki logowania.

Główne pytanie : Dlaczego domyślna powłoka interaktywna jest powłoką logowania w OSX? Dlaczego OSX zdecydował się to zrobić? Oznacza to, że wszystkie instrukcje / samouczki dotyczące rzeczy opartych na powłoce, które wspominają o zmianie rzeczy ~/.bashrc, nie powiodą się w OSX lub odwrotnie ~/.profile. Mimo to, podczas gdy wiele zarzutów można wyrównać w Apple, zatrudnianie niekompetentnych lub idiotycznych deweloperów nie jest jednym z nich. Przypuszczalnie mieli ku temu dobry powód, więc dlaczego?

Podpytania: Czy Terminal.app faktycznie uruchamia interaktywną powłokę logowania lub czy zmieniły zachowanie bash? Czy jest to specyficzne dla Terminal.app czy jest niezależne od emulatora terminala?

terdon
źródło
2
Terminal.app uruchamia powłokę logowania. Nie wiem, dlaczego Apple zdecydowało się to zrobić.
Gilles „SO- przestań być zły”
Nawiasem mówiąc, od MacOS Catalina The domyślna powłoka to zsh .
Basil Bourque,

Odpowiedzi:

33

Sposób, w jaki to miało pracy jest to, że w momencie, gdy pojawi się znak zachęty powłoki, zarówno .profilei .bashrcdotarty. Szczegółowe informacje o tym, jak dojść do tego punktu, mają drugorzędne znaczenie, ale jeśli którykolwiek z plików w ogóle nie zostanie uruchomiony, będziesz mieć powłokę z niepełnymi ustawieniami.

Powodem, dla którego emulatory terminali w Linuksie (i innych systemach opartych na X-ach) nie muszą się uruchamiać .profile, jest to, że normalnie byłyby uruchomione już po zalogowaniu się do X. Ustawienia .profilepowinny być takie, które mogą być dziedziczone przez podprocesy, tak długo, jak są wykonywane raz podczas logowania (np. przez .Xsession), żadne dalsze podpowłoki nie muszą go ponownie uruchamiać.

Jak wyjaśnia strona wiki Debiana, do której prowadzi Alan Shutko:

„Dlaczego .bashrczatem jest osobny plik .bash_profile? Dzieje się tak głównie z powodów historycznych, kiedy maszyny były bardzo wolne w porównaniu do dzisiejszych stacji roboczych. Przetwarzanie poleceń w .profilelub .bash_profilemoże zająć dość dużo czasu, szczególnie na komputerze, na którym dużo pracy musiały zostać wykonane za pomocą zewnętrznych poleceń (pre-bash). Dlatego wprowadzane są trudne początkowe polecenia konfiguracji, które tworzą zmienne środowiskowe, które mogą być przekazywane do procesów potomnych .bash_profile. Wprowadzane są ustawienia przejściowe i aliasy, które nie są dziedziczone w .bashrctaki sposób, aby mogły być ponownie odczytane przez każdą podpowłokę. ”

Te same reguły obowiązują również w OSX, z wyjątkiem jednej rzeczy - GUI OSX nie uruchamia się .profilepo zalogowaniu, najwyraźniej dlatego, że ma własną metodę ładowania ustawień globalnych. Ale to oznacza, że terminal emulator na OSX nie trzeba uruchamiać .profile(mówiąc skorupy uruchamia że jest to powłoka logowania), poza którą kończy się z potencjalnie kalekiego powłoki.


Teraz rodzaj głupiej osobliwości bash, której nie dzieli większość innych powłok, polega na tym, że nie uruchomi się automatycznie, .bashrcjeśli zostanie uruchomiony jako powłoka logowania. Standardowym obejściem tego problemu jest włączenie czegoś takiego jak następujące polecenia .bash_profile:

[[ -e ~/.profile ]] && source ~/.profile    # load generic profile settings
[[ -e ~/.bashrc  ]] && source ~/.bashrc     # load aliases etc.

Alternatywnie można .bash_profilew ogóle nie mieć i po prostu dołączyć .profiledo pliku ogólnego kod specyficzny dla bash, aby uruchomić go w .bashrcrazie potrzeby.

Jeśli domyślny OSX .bash_profilelub .profile tego nie robi, to prawdopodobnie jest to błąd. W każdym razie właściwym obejściem jest po prostu dodanie tych wierszy .bash_profile.


Edycja: Jak zauważa strugee , domyślną powłoką w OSX była tcsh, której zachowanie jest znacznie rozsądniejsze pod tym względem: kiedy działa jako interaktywna powłoka logowania, tcsh automatycznie czyta oba .profile i .tcshrc / .cshrc, a zatem nie potrzebuje żadnych obejść takich jak .bash_profilesztuczka pokazane powyżej.

Na tej podstawie jestem w 99% pewien, że niepowodzenie OSX w dostarczeniu odpowiedniej wartości domyślnej .bash_profilejest spowodowane tym, że po przejściu z tcsh na bash, ludzie z Apple po prostu nie zauważyli tej małej brodawki w zachowaniu startowym basha. W przypadku tcsh takie sztuczki nie były potrzebne - uruchomienie tcsh jako powłoki logowania z emulatora terminala OSX Just Plain Works i robi właściwą rzecz bez takich błędów.

Ilmari Karonen
źródło
1
Dzięki, tak jakby to wszystko wiedziałem. Moje pytanie brzmi: dlaczego OSX zdecydował się skonfigurować w taki sposób, aby stał się .bashrcnieistotny? Dlaczego zdecydowali się, aby wszystkie powłoki logowały się do powłok? O ile wiem, tylko ostatnie zdanie odnosi się do tego i tylko po to, aby powiedzieć, że to błąd.
terdon
1
Nie, problem polega na tym, że uruchamiają powłoki logowania w emulatorach terminali. Pliki kropkowe są domyślnym zachowaniem bash, uruchamianie powłok logowania odczytuje profil itp., A nie bashrc itp. Pytanie brzmi, dlaczego powłoki logowania są uruchamiane zamiast tych, które się nie logują.
terdon
2
Tak, zarówno ja, jak i Alan wyjaśniłem, że dzieje się tak, ponieważ w przeciwieństwie do Linuksa OSX nie wykonuje się, .profilegdy użytkownik loguje się do GUI, więc muszą go wykonać później, aby uzyskać zmienne środowiskowe typu $PATH, które są normalnie ustawione .profile, skonfigurowane poprawnie . Fakt, że jako efekt uboczny powoduje to, że .bashrcnie jest pozyskiwany, jest błędem; możesz spierać się o to, czy jest to błąd w bash, czy w OSX, ale to nie zmienia faktu, że poprawnym zachowaniem byłoby upewnienie się, że zarówno zmienne środowiskowe z, jak .profilei ustawienia konfiguracji bash .bashrcsą załadowane.
Ilmari Karonen
1
Posiadanie .bashrcźródła .profilebyłoby złym pomysłem, ponieważ spowodowałoby ponowne uruchomienie każdej podpowłoki .profile. Jeśli nic więcej, spowodowałoby to powszechne .profileidiomy, takie jak export PATH = "$HOME/bin:$PATH"kontynuowanie przygotowywania zbędnych wpisów $PATH. Posiadanie .profileźródła .bashrcma o wiele większy sens, ale dopiero po sprawdzeniu, czy powłoka, pod którą działa, jest w gruncie rzeczy bash. Posiadanie .bash_profileźródła .profile i .bashrc , jak zasugerowałem powyżej, jest IMO, najbardziej rozsądną opcją.
Ilmari Karonen
2
I odpowiadam na pytanie „dlaczego używają powłoki logowania?” brzmi „ponieważ muszą się ładować .profile”, a odpowiedź na pytanie „dlaczego więc nie .bashrcpochodzą .profile?” to „bo to błąd!” Poważnie, to nie może być celowa decyzja; to po prostu coś, co przeoczyli, prawdopodobnie dlatego, że w ekosystemie Mac skorupy są obywatelami drugiej kategorii, z którymi większość użytkowników nie powinna mieć do czynienia. (Ps. Zobacz także odpowiedź strugee na historyczne wyjaśnienie; prawie na pewno jest to regresja z przejścia z tcsh na bash.)
Ilmari Karonen
14

Głównym powodem, dla którego aplikacje terminalowe X domyślnie uruchamiają powłoki niezwiązane z logowaniem, jest to, że na początku Twoja .Xsession uruchomiłaby .profile, aby skonfigurować początkowe elementy logowania. Następnie, ponieważ wszystko było już skonfigurowane, aplikacje terminalowe nie musiały go uruchamiać, mogły uruchomić .bashrc. Dyskusja na temat tego, dlaczego miałoby to mieć znaczenie, znajduje się na stronie https://wiki.debian.org/DotFiles :

Weźmy xdm jako przykład. Pierre pewnego dnia wraca z wakacji i odkrywa, że ​​jego administrator systemu zainstalował xdm w systemie Debian. Loguje się dobrze, a xdm czyta swój plik .xsession i uruchamia fluxboksa. Wszystko wydaje się być w porządku, dopóki nie pojawi się komunikat o błędzie w niewłaściwych lokalizacjach! Ponieważ zastępuje zmienną LANG w swoim .bash_profile, a ponieważ xdm nigdy nie czyta .bash_profile, jego zmienna LANG jest teraz ustawiona na en_US zamiast fr_CA.

Teraz naiwnym rozwiązaniem tego problemu jest to, że zamiast uruchamiać „xterm”, mógłby skonfigurować swojego menedżera okien, aby uruchamiał „xterm -ls”. Ta flaga informuje xterm, że zamiast uruchamiać normalną powłokę, powinna uruchomić powłokę logowania. W tej konfiguracji xterm spawnuje się / bin / bash, ale wstawia „- / bin / bash” (lub może „-bash”) w wektorze argumentów, więc bash działa jak powłoka logowania. Oznacza to, że za każdym razem, gdy otworzy nowy xterm, będzie czytał / etc / profile i .bash_profile (wbudowane zachowanie bash), a następnie .bashrc (ponieważ .bash_profile tak mówi). Na początku może się wydawać, że działa dobrze - jego pliki kropek nie są duże, więc nawet nie zauważa opóźnienia - ale jest bardziej subtelny problem. Uruchamia także przeglądarkę internetową bezpośrednio z menu Fluxboksa, a przeglądarka internetowa dziedziczy zmienną LANG z fluxboksa, która jest teraz ustawiona na niewłaściwe ustawienia regionalne. Więc chociaż jego xtermy mogą być w porządku, a wszystko, co uruchamia się z jego xtermów, może być w porządku, jego przeglądarka internetowa wciąż podaje mu strony w niewłaściwych lokalizacjach.

W systemie OS X środowiska użytkownika nie są uruchamiane przez stos skryptów powłoki, a uruchomione nie pobiera .profile w żadnym momencie. (To trochę wstyd, ponieważ oznacza to, że ustawianie zmiennych środowiskowych jest o wiele bardziej irytujące, ale takie jest życie.) Ponieważ tak nie jest, kiedy miałoby działać .profile? Tylko jeśli wpiszesz? To wydaje się trochę bezcelowe, ponieważ wiele skrzynek nigdy nie będzie celem ssh. Równie dobrze może spowodować, że terminale będą domyślnie uruchamiać powłoki logowania, aby plik .profile był kiedyś uruchamiany.

Co zatem z .bashrc? Czy to jest bezużyteczne? Nie. Nadal ma cel, jaki miał w czasach VT100. Jest używany za każdym razem, gdy otworzysz powłokę inną niż okno Terminalu. Więc jeśli nie korzystasz z Emacsa lub vi, lub jeśli korzystasz z su.

Alan Shutko
źródło
1
Cytowana strona Debiana wyjaśnia, dlaczego .profileźródła Debiana .bashrc, a nie dlaczego OSX zdecydował, aby wszystkie powłoki domyślnie logowały się do powłok. Właściwie odpowiadasz na inne moje pytanie i dziękuję! Jednak twoja odpowiedź nie wyjaśnia wyboru OSX, a cytat Debiana jest tutaj zupełnie nieistotny, o ile mogę powiedzieć (proszę daj mi znać, jeśli tylko nie rozumiem). Sposób OSX czyni .bashrcetc bezużytecznym i nie czyni go .profilebardziej użytecznym.
terdon
4

Nie wiem, dlaczego to zrobili. Oto moje przypuszczenie.

Na początek warto zauważyć, że w systemie GNU / Linux możesz oczywiście przełączyć się na vt1, vt2 itp. Otrzymujesz tam powłokę logowania. W systemie OS X nie ma odpowiednika. Jedynym sposobem na uzyskanie dostępu do podstaw UNIX jest emulator terminala lub tryb pojedynczego użytkownika (oświadczenie: nigdy tak naprawdę nie korzystałem z trybu pojedynczego użytkownika; jest to IIRC sterowane wierszem poleceń, ale mogę się mylić). Dlatego w systemie OS X wszystko, co domyślne jest w emulatorze, jest domyślne dla całego systemu.

Dlaczego teraz miałbyś ustawić domyślną powłokę logowania? Istnieje kilka (czytaj: niewiele) powodów, dla których mogę to zrobić.

  • Zapewnia spójne wrażenia użytkownika, jeśli SSH do skrzynki. (Jest to szczególnie ważne w przypadku wersji serwerowej OS X - przypuszczalnie jeśli używasz serwera OS X, jesteś nowicjuszem).
  • Domyślna powłoka OS X kiedyś tcsh. Jest to tak szalone przypuszczenie, jak to tylko możliwe, ale może się zdarzyć, że tcshnormalnie coś zrobiło, gdy działało jako powłoka logowania, a historyczny wzór utknął. (Wątpię jednak - może jeden ze starszych bywalców mógłby nam powiedzieć.)
  • „Jesteśmy Apple. Jesteśmy dostawcami największej dystrybucji UNIX na świecie. Nieważne, jak trywialne są nasze powody; jeśli podejmiemy decyzję, Twoje narzędzie musi sobie z tym poradzić”.

Szczerze mówiąc, używam Darwina od około 6 lat i nie mogę odpowiedzieć poprawnie na to pytanie. To też nie ma dla mnie sensu.

Aby odpowiedzieć na twoje pytanie, bashnie jest załatane ani nic (przynajmniej do tego). Domyślny emulator terminala domyślnie uruchamia powłoki logowania i prawdopodobnie iTerm je kopiuje.

strugee
źródło
1
+1 dla wspomnieć tcsh, ponieważ jego zachowanie jest daleko saner pod tym względem niż bash: kiedy rozpoczęła się zarówno do interaktywnej powłoki, tcsh źródła zarówno .profile a .tcshrc/ .cshrcnie wymagając żadnych kluges jak ten dałem na moją odpowiedź. Biorąc to pod uwagę, podejrzewam, że takie zachowanie jest nieusuniętą regresją spowodowaną przejściem z tcsh na bash.
Ilmari Karonen
@IlmariKaronen Czy masz na myśli (tu i tam ), że źródła tcsh .logini .tcshrc/ .cshrc? Źródło tcsh nie miałoby sensu .profile; zazwyczaj zawiera polecenia o shskładni, tcshktóre nie będą akceptowane. Nie mam macOS, ale zrobiłem /bin/tcshmoją powłokę logowania na Ubuntu 16.04. .profilenie jest pozyskiwany. tcsh (1) nie wspomina o tym pliku, podobnie jak tcsh (1) .
Eliah Kagan
3

Jest to aktualizacja do obecnego stanu: odpowiedzi stały się nieaktualne w związku z wydaniem nowych wersji MacOSX i zmianą sposobu logowania.

To pytanie zostało zadane i udzielono odpowiedzi w 2014 roku. Badam ten temat, próbując zbudować wspólny zestaw .bashrc i .bash_profile do użycia w różnych dystrybucjach Linuksa i BSD (jakkolwiek je nazywają, jeśli nie są dystrybucjami).

Niedawno kupiłem używany Mac Mini z zainstalowanym Sierra, więc teraz mam systemy z 10.6, 10.10, 10.11 i 10.12. Chociaż mungowałem starsze (pozostawiając wskazówki do ich poprzedniego statusu), instalacja 10.12 Sierra jest nietknięta.

Wyniki: W wersji 10.12 Sierra NIE ma domyślnego pliku .bashrc, .bash_profile ani .profile. W / etc, są bashrc, bashrc_Apple_Terminal i profil. Zawartość / etc / profile:

# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

if [ "${BASH-no}" != "no" ]; then
    [ -r /etc/bashrc ] && . /etc/bashrc
fi

Zawartość / etc / bashrc:

# System-wide .bashrc file for interactive bash(1) shells.
if [ -z "$PS1" ]; then
   return
fi

PS1='\h:\W \u\$ '
# Make bash check its window size after a process completes
shopt -s checkwinsize

[ -r "/etc/bashrc_$TERM_PROGRAM" ] && . "/etc/bashrc_$TERM_PROGRAM"

Skrypt / etc / bashrc_Apple_Terminal ustawia zmienną PROMPT_COMMAND i konfiguruje mechanizm zachowania stanu sesji dla każdego terminala; jeśli aplikacja terminalu zostanie zamknięta, status poprzedniej sesji zostanie przywrócony po ponownym uruchomieniu aplikacji. W przeciwnym razie prawie nic (minimalne $ PS1) nie jest ustawione w / etc / bashrc, pozostawiając wszelkie inne dostosowania (prawdziwe $ PS1, aliasy, funkcje) do ustawienia w ~ / .bashrc i $ PATH w .bash_profile (lub w .profile , pochodzi z .bash_profile).

Potwierdziłem, że iTerm2 zachowuje się tak samo jak aplikacja Terminal, z tym wyjątkiem, że domyślne zachowanie rozpoczęcia sesji logowania jest widoczne i można je edytować.

Jeśli uruchomisz sesję terminala XTerm X11 (obecnie XQuartz), zobaczysz sesję bez logowania, taką samą jak w systemie Linux; .bash_profile (lub .profile) jest pomijany i dostajesz tylko .bashrc.

A oto moja odpowiedź:

Chociaż aplikacja Terminal twierdzi, że jest xtermem (TERM = xterm-256color), nie ustawia zmiennej $ DISPLAY, chyba że X11 jest zainstalowany. Widzimy symulację środowiska X, ale nie do końca prawdziwego. Jeśli SSH przełączysz do innego systemu za pomocą przełącznika -X (włącz przekazywanie X11), zakończy się to niepowodzeniem, ponieważ nie ma zmiennej $ DISPLAY. Jeśli zainstalowałeś X11, a następnie SSH w innym systemie, przekazywanie X11 powiedzie się.

Konkluzja (i krótka odpowiedź): aplikacja Terminal nie jest prawdziwym terminalem X11 (nie ustawia $ DISPLAY); zachowuje się bardziej jak logowanie SSH niż sesja XTerm, ponieważ musi być sesją logowania, aby ustawić wartości z / etc / profile i ~ / .bash_profile lub ~ / .profile

pączki
źródło
0

Odpowiedzi powyżej wyjaśniono, dlaczego interaktywne muszli powłok zgłoszeniowych na MacOS fabrycznie: ustawienia /etc/profile, ~/.profilesą dziedziczone przez powłoki bez logowania w systemach opartych na X, ale nie na MacOS . Chcę tutaj przypomnieć, że powinieneś zawsze używać powłoki logowania na macOS z powodu istnienia path_helper:

 cat /etc/profile # or cat /etc/zprofile
# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

if [ "${BASH-no}" != "no" ]; then
    [ -r /etc/bashrc ] && . /etc/bashrc
fi

path_helperNarzędzie odczytuje zawartość tych plików w katalogach /etc/paths.di /etc/manpaths.d i dołącza do ich zawartości PATHi MANPATHśrodowiska zmiennych odpowiednio. ( MANPATHZmienna środowiskowa nie zostanie zmodyfikowana, chyba że jest już ustawiona w środowisku.)

Jeśli używasz powłoki niezalogowanej, niektóre ścieżki nie zostaną zaimportowane.

Myślę, że dla deweloperów zawsze dobrym pomysłem jest umieszczenie pliku w /etc/paths.dcelu zaimportowania wartości ścieżek, ale nie symlinkowanie wywoływalnych plików binarnych w lokalizacjach takich jak /usr/binlub /bin. (Domyślnie PATHjest /usr/bin:/bin:/usr/sbin:/sbin. Nie wszyscy używają Homebrew lub MacPorts do dodawania niestandardowych wartości PATH. Dlatego nie zawsze jest bezpieczne miejsce na umieszczenie dowiązań symbolicznych wywoływanych poleceń).

Oto przykład plików w /etc/paths.d. Zasadniczo stawiasz jedną wartość w każdym wierszu.

 cat /etc/paths.d/Wireshark
/Applications/Wireshark.app/Contents/MacOS

Odniesienie:

Simba
źródło