Unterschied zwischen Login-Shell und Nicht-Login-Shell?

318

Ich verstehe den grundlegenden Unterschied zwischen einer interaktiven und einer nicht interaktiven Shell. Aber was unterscheidet eine Login-Shell genau von einer Nicht-Login-Shell?

Können Sie Beispiele für die Verwendung einer nicht angemeldeten interaktiven Shell geben?

Igorio
quelle
45
Ich denke, die Frage ist besser formuliert als " Warum ist es uns wichtig, Anmelde- und Nicht-Anmelde-Shells zu unterscheiden?" Viele Stellen im Internet verraten uns bereits, worin die Unterschiede bestehen, welche Startdateien jeweils gelesen werden. aber keines von ihnen scheint das "Warum" auf zufriedenstellende und überzeugende Weise zu beantworten. Beispielanwendungsfälle, in denen Sie definitiv das eine oder andere Verhalten nicht wollen, wären großartig.
Kal
2
@Kal Das müsste eine andere Frage sein, da hier eigentlich keine Antwort darauf gibt. Edit: Eigentlich ist es hier: WARUM eine Login- Shell über eine Nicht-Login- Shell? .
Skippy le Grand Gourou

Antworten:

304

Eine Anmeldeshell ist der erste Prozess, der unter Ihrer Benutzer-ID ausgeführt wird, wenn Sie sich für eine interaktive Sitzung anmelden. Der Anmeldeprozess weist die Shell an, sich wie eine Anmelde-Shell mit einer Konvention zu verhalten: Übergabe des Arguments 0, das normalerweise der Name der ausführbaren Shell ist, mit -vorangestelltem Zeichen (z. B. -bashwährend dies normalerweise der Fall wäre bash. Anmelde-Shells lesen normalerweise eine Datei, die dies tut Dinge wie Umgebungsvariablen: /etc/profileund ~/.profilefür die traditionelle Bourne - Shell, ~/.bash_profilezusätzlich für bash , /etc/zprofileund ~/.zprofilefür zsh , /etc/csh.loginund ~/.loginfür csh etc.

Wenn Sie sich an einer Textkonsole oder über SSH oder mit anmeldensu - , erhalten Sie eine interaktive Anmeldeshell . Wenn Sie sich im Grafikmodus (auf einem X-Display-Manager ) anmelden, erhalten Sie keine Anmeldeshell, sondern einen Sitzungs- oder Fenstermanager.

Es kommt selten vor, dass eine nicht interaktive Anmeldeshell ausgeführt wird. Bei einigen X-Einstellungen erfolgt dies jedoch, wenn Sie sich mit einem Display-Manager anmelden, um das Lesen der Profildateien zu arrangieren. Andere Einstellungen (dies hängt von der Distribution und dem Display-Manager ab) lesen /etc/profileund ~/.profileexplizit oder lesen sie nicht. Eine andere Möglichkeit, eine nicht interaktive Anmeldeshell zu erhalten, besteht darin, sich remote mit einem Befehl anzumelden, der über die Standardeingabe übergeben wird und kein Terminal ist ssh example.com <my-script-which-is-stored-locally(im Gegensatz zu ssh example.com my-script-which-is-on-the-remote-machineeiner nicht interaktiven Shell, die keine Anmeldeshell ausführt).

Wenn Sie eine Shell in einem Terminal in einer vorhandenen Sitzung starten (Bildschirm, X-Terminal, Emacs-Terminalpuffer, eine Shell in einer anderen usw.), erhalten Sie eine interaktive Shell ohne Anmeldung . Diese Shell liest möglicherweise eine Shell-Konfigurationsdatei ( ~/.bashrcfür Bash, die als und für zsh aufgerufen bashwird , und für csh die Datei, die von der Variablen für POSIX / XSI-kompatible Shells wie dash, ksh und bash angegeben wird, wenn sie als , sofern gesetzt und aufgerufen wird für mksh usw.)./etc/zshrc~/.zshrc/etc/csh.cshrc~/.cshrcENVsh$ENV~/.mkshrc

Wenn eine Shell ein Skript oder einen Befehl ausführt, der über die Befehlszeile übergeben wird, handelt es sich um eine nicht interaktive Shell ohne Anmeldung . Solche Shells werden ständig ausgeführt: Wenn ein Programm ein anderes Programm aufruft, wird häufig ein winziges Skript in einer Shell ausgeführt, um dieses andere Programm aufzurufen. Einige Shells lesen in diesem Fall eine Startdatei (bash führt die durch die BASH_ENVVariable angegebene Datei aus , zsh läuft /etc/zshenvund ~/.zshenv), aber dies ist riskant: Die Shell kann in allen möglichen Kontexten aufgerufen werden, und Sie können kaum etwas tun, was möglicherweise nicht möglich ist kaputt machen.

Ich vereinfache ein wenig, siehe Handbuch für die blutigen Details.

Gilles
quelle
2
Können Sie ein Beispiel geben, wie Sie bashals nicht interaktive Anmeldeshell ausgeführt werden?
Piotr Dobrogost
13
@PiotrDobrogostecho $- | bash -lx
Gilles
1
Ich weiß nicht, ob dies im Allgemeinen zutrifft, aber ich möchte darauf hinweisen, dass ich beim Öffnen eines neuen Terminals (unter OSX mit Standardeinstellungen) eine Anmeldeshell erhalte, obwohl ich meinen Benutzernamen oder mein Kennwort nie eingebe.
Kevin Wheeler
4
@KevinWheeler Unter OSX führt die Terminal-Anwendung standardmäßig eine Anmeldeshell aus. (Wie ich erkläre, entscheidet das Programm, das die Shell startet, ob die Shell als Anmeldeshell fungiert.) Dies ist nicht die normale Vorgehensweise.
Gilles
2
@IAmJulianAcosta Wenn FOOes sich um eine Umgebungsvariable handelt (dh sie .profileenthält export FOO=something), steht sie allen Unterprozessen zur Verfügung, einschließlich foo.sh. Wenn Sie ändern , .profileum export FOO=something_elsedann ./foo.shnoch gedruckt wird , somethingbis zum nächsten Mal , wenn Sie sich anmelden.
Gilles
48

So stellen Sie fest, ob Sie sich in einer Anmeldeshell befinden:

prompt> echo $0
-bash # "-" is the first character. Therefore, this is a login shell.

prompt> echo $0
bash # "-" is NOT the first character. This is NOT a login shell.

In Bash können Sie auch Folgendes verwenden shopt login_shell:

prompt> shopt login_shell
login_shell     off

(oder onin einer Login-Shell).

Informationen finden Sie in man bash(Suche nach Invocation). Hier ist ein Auszug:

Eine Login-Shell ist eine Shell, deren erstes Zeichen des Arguments Null ein - ist, oder eine Shell, die mit der Option --login gestartet wurde.

Sie können dies selbst testen. Immer wenn Sie SSH verwenden, verwenden Sie eine Login-Shell. Zum Beispiel:

prompt> ssh user@localhost
user@localhost's password:
prompt> echo $0
-bash

Die Verwendung einer Login-Shell hat die Bedeutung, dass alle Einstellungen in /home/user/.bash_profileausgeführt werden. Hier noch ein bisschen mehr Infos bei Interesse (von man bash)

"Wenn bash als interaktive Anmeldeshell oder als nicht interaktive Shell mit der Option --login aufgerufen wird, werden zuerst Befehle aus der Datei / etc / profile gelesen und ausgeführt, sofern diese Datei vorhanden ist. Nachdem diese Datei gelesen wurde, wird sie gelesen sucht nach ~/.bash_profile, ~/.bash_loginund ~/.profilein dieser Reihenfolge und liest und führt Befehle von dem ersten aus, der vorhanden und lesbar ist. Die Option --noprofile kann verwendet werden, wenn die Shell gestartet wird, um dieses Verhalten zu unterbinden. "

Timothy Pulliam
quelle
23

In einer Login-Shell argv[0][0] == '-'. So weiß es, dass es sich um eine Login-Shell handelt.

In einigen Situationen verhält es sich je nach Status der "Anmeldeshell" unterschiedlich. ZB würde eine Shell, die keine Login-Shell ist, keinen "Logout" -Befehl ausführen.

BOPOHOK
quelle
4
Laut man bash, mit Hervorhebung hinzugefügt, "Eine Login-Shell ist eine, deren erstes Zeichen des Arguments Null ein - ist, oder eine, die mit der Option --login begonnen wurde. "
Wildcard
18

Eine Shell, die in einem neuen Terminal in einer GUI gestartet wird, ist eine interaktive Shell ohne Anmeldung. Es würde zum Beispiel Ihre .bashrc-Datei als Quelle verwenden, nicht jedoch Ihr .profile.

julianisch
quelle
4

Ich werde auf die großartige Antwort von Gilles eingehen, kombiniert mit Timothys Methode zur Überprüfung des Login-Shell-Typs.

Wenn Sie sich selbst davon überzeugen möchten, probieren Sie die folgenden Ausschnitte und Szenarien aus.

Überprüfen, ob die Shell (nicht) interaktiv ist

if tty -s; then echo 'This is interactive shell.'; else echo 'This is non-interactive shell.'; fi

Überprüfen, ob die Shell (nicht-) angemeldet ist

Wenn die Ausgabe von mit echo $0beginnt -, ist dies die Login-Shell ( echo $0Ausgabebeispiel:) -bash. Ansonsten handelt es sich um eine Nicht-Login-Shell ( echo $0Ausgabebeispiel:) bash.

if echo $0 | grep -e ^\- 2>&1>/dev/null; then echo "This is login shell."; else echo "This is non-login shell."; fi;

Kombinieren wir die beiden oben genannten Elemente, um beide Informationen gleichzeitig zu erhalten:

THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; 
THIS_SHELL_LOGIN_TYPE='non-login'; 
if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; 
if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

Szenarien:

Typische SSH-Sitzung ohne spezielle Optionen

ssh ubuntu@34.247.105.87
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

ubuntu@ip-172-31-0-70:~$ THIS_SHELL_INTERACTIVE_TYPE='non-interactive';
ubuntu@ip-172-31-0-70:~$ THIS_SHELL_LOGIN_TYPE='non-login';
ubuntu@ip-172-31-0-70:~$ if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi;
ubuntu@ip-172-31-0-70:~$ if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
ubuntu@ip-172-31-0-70:~$ echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

interactive/login

Skript ausführen oder explizit über neue Shell ausführen

ubuntu@ip-172-31-0-70:~$  bash -c 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; 
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

Lokales Skript remote ausführen

ssh ubuntu@34.247.105.87 < checkmy.sh
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

non-interactive/login

Ausführen eines Befehls über SSH aus der Ferne

ssh ubuntu@34.247.105.87 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

non-interactive/non-login

Führen Sie einen Befehl über ssh mit -tswitch aus der Ferne aus

Sie können die interaktive Shell explizit anfordern, wenn Sie den Befehl remote über ssh mithilfe von -tswitch ausführen möchten .

ssh ubuntu@34.247.105.87 -t 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

Hinweis: Auf Thema , warum remote Befehl nicht ausgeführt ist login shellmehr Infos hier .

Patrik Stas
quelle