Warum sind interaktive Shells standardmäßig in OSX-Anmeldeshells enthalten?

43

Unter Linux und meines Wissens auf allen Unix-Systemen führen Terminalemulatoren standardmäßig interaktive Shells ohne Anmeldung aus. Dies bedeutet, dass die gestartete Shell für bash:

Wenn eine interaktive Shell gestartet wird, die keine Anmeldeshell ist, liest bash Befehle aus /etc/bash.bashrcund führt sie aus ~/.bashrc, sofern diese Dateien vorhanden sind. Dies kann durch Verwendung der --norc Option verhindert werden.

Die --rcfile Dateioption erzwingt, dass Bash anstelle von /etc/bash.bashrcund Befehle aus der Datei liest und ausführt ~/.bashrc.

Und für Login-Shells:

Wenn bash als interaktive Anmeldeshell oder als nicht interaktive Shell mit der --loginOption aufgerufen wird , werden zuerst Befehle aus der Datei gelesen und ausgeführt /etc/profile, sofern diese Datei vorhanden ist. Nachdem die Datei zu lesen, sucht er nach ~/.bash_profile, ~/.bash_loginund ~/.profilein dieser Reihenfolge, und liest und die Befehle ausführt , von der ersten , die lesbar existiert und ist.

Die --noprofileOption kann verwendet werden, wenn die Shell gestartet wird, um dieses Verhalten zu unterbinden.

Auf OSX, aber die Standard - Shell in dem Standardanschluss (Terminal.app) tatsächlich Quellen gestartet (die bash) ~/.bash_profileoder ~.profileusw. Mit anderen Worten, wirkt es wie ein Login - Shell.

Hauptfrage : Warum ist die standardmäßige interaktive Shell eine Anmeldeshell unter OSX? Warum hat sich OSX dafür entschieden? Dies bedeutet, dass alle Anweisungen / Tutorials für Shell-basierte Dinge, in denen das Ändern von Dingen erwähnt ~/.bashrcwird, unter OSX fehlschlagen oder umgekehrt ~/.profile. Obwohl viele Vorwürfe gegen Apple erhoben werden können, gehört die Einstellung von inkompetenten oder idiotischen Entwicklern nicht dazu. Vermutlich hatten sie einen guten Grund dafür, also warum?

Unterfragen: Führt Terminal.app tatsächlich eine interaktive Anmeldeshell aus oder haben sie das Verhalten von bash geändert? Ist dies spezifisch für Terminal.app oder unabhängig vom Terminalemulator?

terdon
quelle
2
Terminal.app führt eine Login-Shell aus. Ich weiß nicht, warum Apple das gewählt hat.
Gilles 'SO - hör auf böse zu sein'
Ab macOS Catalina ist die Standard-Shell übrigens zsh .
Basil Bourque

Antworten:

33

Die Art und Weise es sollte Arbeit ist , dass an dem Punkt , wenn Sie ein Shell - Eingabeaufforderung erhalten, die beide .profileund .bashrcausgeführt wurden. Die genauen Details, wie Sie zu diesem Punkt gelangen, sind von untergeordneter Bedeutung. Wenn jedoch eine der Dateien überhaupt nicht ausgeführt würde, hätten Sie eine Shell mit unvollständigen Einstellungen.

Der Grund Terminal - Emulatoren auf Linux (und anderen X-basierten Systemen) nicht benötigen laufen .profileselbst ist , dass es in der Regel bereits ausgeführt worden ist , wenn Sie in X. angemeldet : Die Einstellungen in .profilesollen von der Art sein , die sein kann , von Subprozessen geerbt, so lange es einmalig ausgeführt wird, wenn Sie sich anmelden (zB über .Xsession), müssen weitere Subshells es nicht erneut ausführen.

Wie die von Alan Shutko verlinkte Debian-Wiki-Seite erklärt:

„Warum ist .bashrceine separate Datei aus .bash_profile, dann? Das ist für meist historischen Gründen erfolgt, wenn Maschinen waren extrem langsam im Vergleich zu heutigen Workstations. Die Verarbeitung der Befehle in .profileoder .bash_profilekönnte ziemlich lange dauern, vor allem auf einem Computer , auf dem ein großer Teil der Arbeit mussten von externen Befehlen ausgeführt werden (Pre-Bash), damit die schwierigen anfänglichen Setup-Befehle, mit denen Umgebungsvariablen erstellt werden, die an untergeordnete Prozesse weitergegeben werden können, .bash_profileeingegeben werden in .bashrcso dass sie wieder liest von jedem Sub - Shell sein können.“

Die gleichen Regeln gelten auch für OSX, mit der Ausnahme, dass die OSX-Benutzeroberfläche .profilebeim Anmelden nicht ausgeführt wird , anscheinend weil sie eine eigene Methode zum Laden globaler Einstellungen hat. Aber das bedeutet , dass ein Terminal - Emulator auf OSX funktioniert ausführen muß .profile(von dem Shell startet es zu sagen , dass es ein Login - Shell), sonst würde man mit einem potenziell verkrüppelten Schale enden.


Nun, eine Art alberne Besonderheit von bash, die von den meisten anderen Shells nicht geteilt wird, ist, dass es nicht automatisch ausgeführt wird, .bashrcwenn es als Login-Shell gestartet wird. Die Standardumgehung dafür besteht darin, in etwa die folgenden Befehle einzuschließen .bash_profile:

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

Alternativ ist es möglich, überhaupt keinen .bash_profilezu haben und nur bash-spezifischen Code in die generische .profileDatei aufzunehmen, um sie .bashrcbei Bedarf auszuführen .

Wenn OSX dies standardmäßig tut.bash_profile oder .profile nicht , ist das wahrscheinlich ein Fehler. In jedem Fall müssen diese Zeilen einfach hinzugefügt werden .bash_profile.


Bearbeiten: Die Standard-Shell unter OSX war, wie wir bereits bemerkt haben , tcsh. Ihr Verhalten ist in dieser Hinsicht weitaus vernünftiger: Wenn tcsh als interaktive Anmeldeshell ausgeführt wird, liest es automatisch beide .profile und .tcshrc / .cshrcoder benötigt daher keine Problemumgehungen wie diesen .bash_profileTrick oben gezeigt.

Auf dieser Basis bin ich mir zu 99% sicher, dass das Versagen von OSX darin .bash_profilebesteht, dass die Leute von Apple beim Wechsel von tcsh zu bash diese kleine Warze im Startverhalten von bash einfach nicht bemerkt haben. Mit tcsh waren solche Tricks nicht erforderlich - das Starten von tcsh als Login-Shell von einem OSX-Terminalemulator aus. Just Plain Works und das richtige Vorgehen ohne solche Probleme.

Ilmari Karonen
quelle
1
Danke, ich wusste das alles. Meine Frage ist, warum OSX so eingerichtet hat, dass es .bashrcirrelevant wird. Warum haben sie sich entschieden, alle Shells als Login-Shells zu verwenden? Soweit ich das beurteilen kann, spricht nur Ihr letzter Satz das an und nur um zu sagen, dass es ein Fehler ist.
Terdon
1
Nein, das Problem ist, dass sie Login-Shells in ihren Terminal-Emulatoren starten. Die Punktedateien sind Standard-Bash-Verhalten, das Starten von Login-Shells liest Profile usw., nicht Bash-Code usw. Die Frage ist, warum Login-Shells anstelle von Nicht-Login-Shells ausgeführt werden.
Terdon
2
Ja, und sowohl ich als auch Alan haben erklärt, dass OSX im Gegensatz zu Linux nicht ausgeführt wird, .profilewenn sich der Benutzer bei der GUI anmeldet. Daher müssen sie es später ausführen, um Umgebungsvariablen wie $PATHdie normalerweise festgelegten .profilerichtig zu konfigurieren . Die Tatsache, dass dies als Nebeneffekt dazu führt, dass .bashrckeine Quellen gefunden werden, ist ein Fehler. Sie können darüber streiten, ob es sich um einen Fehler in Bash oder in OSX handelt, aber das ändert nichts an der Tatsache, dass das richtige Verhalten darin besteht, sicherzustellen, dass sowohl die Umgebungsvariablen von .profileals auch die Bash-Konfigurationseinstellung von .bashrcgeladen werden.
Ilmari Karonen
1
Mit .bashrcQuelle .profilewäre eine schlechte Idee sein, da es jeden Subshell Wiederholungslauf verursachen würde .profile. Wenn nichts anderes, würde dies dazu führen, dass gängige .profileRedewendungen export PATH = "$HOME/bin:$PATH"redundanten Einträgen voranstellen $PATH. Nachdem .profileQuelle .bashrcmacht viel mehr Sinn, aber nur nach Überprüfung , dass die Schale unter fließendem ist, in der Tat, bash. Mit .bash_profileQuelle beide .profile und .bashrc , wie ich oben vorgeschlagen, ist, IMO, die vernünftigste Option.
Ilmari Karonen
2
Und ich sage die Antwort auf "Warum verwenden sie eine Login-Shell?" ist „ weil sie zu laden müssen .profile“, während die Antwort auf „warum nicht sie Quelle .bashrcaus .profile, dann?“ ist "weil es ein Fehler ist!" Im Ernst, das kann unmöglich eine absichtliche Entscheidung sein. Es ist nur etwas, das sie übersehen haben, vermutlich, weil Muscheln im Mac-Ökosystem Bürger zweiter Klasse sind, mit denen sich die meisten Benutzer nicht befassen sollten. (Ps. Siehe auch die Antwort von strugee für eine historische Erklärung; es ist mit ziemlicher Sicherheit eine Regression von der Umstellung von tcsh auf bash.)
Ilmari Karonen
14

Der Hauptgrund dafür, dass X-Terminalanwendungen standardmäßig nicht angemeldete Shells ausführen, ist, dass Ihre .Xsession zu Beginn das .profile ausgeführt hat, um Ihre anfänglichen Anmeldeelemente einzurichten. Da dies alles bereits eingerichtet war, mussten Terminal-Apps es nicht ausführen, sondern konnten die .bashrc-Datei ausführen. Die Diskussion, warum dies wichtig ist, finden Sie unter https://wiki.debian.org/DotFiles :

Nehmen wir als Beispiel xdm. Pierre kommt eines Tages aus dem Urlaub zurück und stellt fest, dass sein Systemadministrator xdm auf dem Debian-System installiert hat. Er meldet sich gut an, und xdm liest seine .xsession-Datei und führt fluxbox aus. Alles scheint in Ordnung zu sein, bis er eine Fehlermeldung im falschen Gebietsschema erhält! Da er die LANG-Variable in seinem .bash_profile überschreibt und xdm niemals .bash_profile liest, wird seine LANG-Variable jetzt auf en_US anstelle von fr_CA gesetzt.

Die naive Lösung für dieses Problem besteht nun darin, dass er seinen Fenstermanager so konfigurieren kann, dass er "xterm -ls" startet, anstatt "xterm" zu starten. Dieses Flag teilt xterm mit, dass anstelle einer normalen Shell eine Login-Shell gestartet werden soll. Unter diesem Setup erzeugt xterm / bin / bash, fügt jedoch "- / bin / bash" (oder vielleicht "-bash") in den Argumentvektor ein, sodass bash wie eine Login-Shell funktioniert. Dies bedeutet, dass jedes Mal, wenn er ein neues xterm öffnet, es / etc / profile und .bash_profile (eingebautes Bash-Verhalten) und dann .bashrc (weil .bash_profile dies verlangt) liest. Dies scheint zunächst in Ordnung zu sein - seine Punktedateien sind nicht schwer, sodass er die Verzögerung nicht einmal bemerkt -, aber es gibt ein subtileres Problem. Er startet auch einen Webbrowser direkt aus seinem Fluxbox-Menü. und der Webbrowser erbt die LANG-Variable von fluxbox, die jetzt auf das falsche Gebietsschema eingestellt ist. Obwohl seine xterms in Ordnung sind und alles, was von seinen xterms aus gestartet wird, in Ordnung ist, zeigt ihm sein Webbrowser immer noch Seiten in der falschen Ländereinstellung an.

Unter OS X werden die Benutzerumgebungen nicht von einem Stapel von Shell-Skripten gestartet, und launchd gibt zu keinem Zeitpunkt .profile als Quelle aus. (Das ist eine Schande, da es viel ärgerlicher ist, Umgebungsvariablen zu setzen, aber so ist das Leben.) Da dies nicht der Fall ist, wann würde es ausgeführt werden .profile? Nur wenn du reinkommst? Das scheint irgendwie sinnlos zu sein, da viele Kisten niemals Ziele von ssh sein werden. Könnte auch dazu führen, dass die Terminals standardmäßig Login-Shells ausführen, so dass .profile irgendwann ausgeführt wird.

Was ist dann mit .bashrc? Ist es nutzlos Nein, es hat immer noch den Zweck, den es in den Tagen des VT100 hatte. Es wird immer dann verwendet, wenn Sie eine andere Shell öffnen als ein Terminal-Fenster. Also, wenn Sie Emacs oder vi nicht mehr verwenden, oder wenn Sie einen su-Benutzer haben.

Alan Shutko
quelle
1
Die Debian-Seite, die Sie zitieren, erklärt, warum Debian- .profileQuellen .bashrcund nicht, warum OSX beschlossen hat, alle Shells als Login-Shells festzulegen. Eigentlich beantwortest du eine andere Frage von mir und danke! Ihre Antwort erklärt jedoch nicht die Wahl von OSX und das Debian-Zitat ist hier, soweit ich das beurteilen kann, völlig irrelevant (lassen Sie es mich bitte wissen, wenn ich nur den Punkt verfehle). Der OSX-Weg macht .bashrcetc unbrauchbar und macht nicht .profilemehr brauchbar.
Terdon
4

Ich weiß nicht, warum sie das getan hätten. Hier ist jedoch meine Vermutung.

Zunächst ist zu beachten, dass Sie auf einem GNU / Linux-System natürlich zu vt1, vt2 usw. wechseln können. Dort erhalten Sie eine Anmeldeshell. Auf einem OS X-System gibt es kein Äquivalent. Der einzige Weg, auf die UNIX-Grundlagen zuzugreifen, ist über einen Terminalemulator oder über den Einzelbenutzermodus (Haftungsausschluss: Ich habe noch nie den Einzelbenutzermodus verwendet; es ist befehlszeilengesteuertes IIRC, aber ich kann mich irren). Daher ist in OS X die Standardeinstellung im Emulator die Standardeinstellung für das gesamte System.

Warum sollten Sie als Standard eine Anmeldeshell festlegen? Es gibt ein paar (gelesen: nicht viele) Gründe, die ich mir vorstellen kann, dies zu tun.

  • Es bietet eine konsistente Benutzererfahrung, wenn Sie SSH in die Box. (Besonders wichtig für die Server-Edition von OS X - vermutlich, wenn Sie einen OS X-Server ausführen, sind Sie ein Neuling.)
  • Die Standard-Shell von OS X war früher tcsh. Dies ist ungefähr eine wilde Vermutung, die Sie bekommen können, aber es kann sein, dass tcshnormalerweise etwas passiert ist, wenn es als Login-Shell ausgeführt wird, und das historische Muster steckt. (Ich bezweifle es aber - vielleicht könnte es uns einer der älteren Stammgäste sagen.)
  • "Wir sind Apple. Wir sind die Anbieter der größten UNIX-Distribution der Welt. Es spielt keine Rolle, aus welchen trivialen Gründen wir handeln. Wenn wir eine Entscheidung treffen, muss Ihr Tool damit umgehen."

Ehrlich gesagt benutze ich Darwin seit ca. 6 Jahren und kann diese Frage nicht richtig beantworten. Das ergibt für mich auch keinen Sinn.

Um Ihre Unterfrage zu beantworten, bashist noch nichts gepatcht (zumindest dafür). Der Standard-Terminal-Emulator führt standardmäßig Login-Shells aus, und vermutlich kopiert iTerm diese.

strugee
quelle
1
+1 für die Erwähnung von tcsh, da sein Verhalten in dieser Hinsicht weitaus vernünftiger ist als das von bash: Wenn tcsh als interaktive Anmeldeshell gestartet wird, bezieht es beide Quellen .profileund .tcshrc/ oder .cshrcbenötigt keine Kluges wie die, die ich in meiner Antwort angegeben habe. Angesichts dessen vermute ich, dass dieses Verhalten eine unfixierte Regression ist, die durch den Wechsel von tcsh zu bash verursacht wurde.
Ilmari Karonen
@IlmariKaronen Meinst du (hier und da ), dass tcsh Quellen .loginund .tcshrc/ oder .cshrc? Es würde keinen Sinn machen, tcsh zu beziehen .profile. Es enthält normalerweise Befehle mit einer shSyntax, tcshdie nicht akzeptiert werden. Ich habe kein MacOS, aber ich habe /bin/tcshmeine Login-Shell unter Ubuntu 16.04 erstellt. .profilewird nicht bezogen. tcsh (1) erwähnt diese Datei nicht und tcsh (1) auch nicht .
Eliah Kagan
3

Dies ist eine Aktualisierung des aktuellen Status: Die Antworten sind veraltet, da neue MacOSX-Versionen veröffentlicht wurden und sich das Anmeldeverhalten geändert hat.

Diese Frage wurde 2014 gestellt und beantwortet. Ich habe mich mit dem Thema befasst, um ein gemeinsames .bashrc- und .bash_profile-Set zu erstellen, das für verschiedene Linux- und BSD-Distributionen (wie auch immer sie genannt werden, wenn sie keine Distributionen sind) verwendet werden soll.

Ich habe kürzlich einen gebrauchten Mac Mini mit Sierra gekauft und habe nun Systeme mit 10.6, 10.10, 10.11 und 10.12. Obwohl ich die älteren gemengt habe (und Hinweise auf ihren vorherigen Status hinterlassen habe), bleibt die Installation von Sierra 10.12 unberührt.

Ergebnisse: In 10.12 Sierra wurden KEINE Standardeinstellungen für .bashrc, .bash_profile oder .profile erstellt. In / etc gibt es bashrc, bashrc_Apple_Terminal und profile. Inhalt von / 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

Inhalt von / 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"

Das Skript / etc / bashrc_Apple_Terminal legt die Variable PROMPT_COMMAND fest und richtet einen Mechanismus zum Beibehalten des Sitzungsstatus für jedes Terminal ein. Wenn die Terminal-App beendet wird, wird der Status der vorherigen Sitzung wiederhergestellt, wenn die App erneut gestartet wird. Andernfalls wird fast nichts (minimal $ PS1) in / etc / bashrc festgelegt, und alle anderen Anpassungen (echte $ PS1, Aliase, Funktionen) müssen in den Einstellungen ~ / .bashrc und $ PATH in .bash_profile (oder in .profile) festgelegt werden , bezogen von .bash_profile).

Ich habe bestätigt, dass iTerm2 sich genauso verhält wie die Terminal-App, außer dass das Standardverhalten beim Starten einer Anmeldesitzung sichtbar ist und bearbeitet werden kann.

Wenn Sie eine X11 (jetzt XQuartz) XTerm-Terminalsitzung ausführen, wird eine Sitzung ohne Anmeldung angezeigt, genau wie auf einem Linux-System. .bash_profile (oder .profile) wird übersprungen und Sie erhalten nur .bashrc.

Und hier ist meine Antwort:

Obwohl die Terminal-App angibt, ein xterm zu sein (TERM = xterm-256color), wird die Variable $ DISPLAY nur festgelegt, wenn X11 installiert ist. Wir sehen eine Simulation einer X-Umgebung, aber keine ganz reale. Wenn Sie mit dem Schalter -X eine SSH-Verbindung zu einem anderen System herstellen (X11-Weiterleitung aktivieren), schlägt dies fehl, da keine Variable $ DISPLAY vorhanden ist. Wenn Sie X11 und dann SSH auf einem anderen System installiert haben, ist die X11-Weiterleitung erfolgreich.

Fazit (und kurze Antwort): Die Terminal-App ist kein echtes X11-Terminal (setzt $ DISPLAY nicht); Es verhält sich viel mehr wie eine SSH-Anmeldung als eine XTerm-Sitzung, da es eine Anmeldesitzung sein muss, um Werte aus / etc / profile und ~ / .bash_profile oder ~ / .profile festzulegen

Donls
quelle
0

Die obigen Antworten erläuterten den Grund, warum interaktive Shells unter macOS standardmäßig Anmeldeshells sind: Einstellungen in /etc/profile, ~/.profilewerden auf X-basierten Systemen von einer Shell ohne Anmeldung übernommen, jedoch nicht unter macOS . Hier möchte ich Sie daran erinnern, dass Sie unter macOS immer die Login-Shell verwenden sollten, da 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

Das path_helperDienstprogramm liest den Inhalt der Dateien in den Verzeichnissen /etc/paths.dund /etc/manpaths.d und fügt ihren Inhalt in die PATHund MANPATHUmgebungsvariablen sind. (Die MANPATHUmgebungsvariable wird nur geändert, wenn sie bereits in der Umgebung festgelegt wurde.)

Wenn Sie eine Shell ohne Anmeldung verwenden, werden einige Pfade nicht importiert.

Ich denke, es ist immer eine gute Idee für Entwickler, eine Datei zu erstellen /etc/paths.d, um ihre Pfadwerte zu importieren, aber die aufrufbaren Binärdateien nicht mit Speicherorten wie /usr/binoder zu verknüpfen /bin. (Die Standardeinstellung PATHist /usr/bin:/bin:/usr/sbin:/sbin. Nicht jeder verwendet Homebrew oder MacPorts, um benutzerdefinierte Werte hinzuzufügen PATH. Daher gibt es nicht immer einen sicheren Ort, um die Symlinks aufrufbarer Befehle zu platzieren.)

Hier ist ein Beispiel für Dateien in /etc/paths.d. Grundsätzlich schreiben Sie pro Zeile einen Wert.

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

Referenz:

Simba
quelle