登录外壳程序和非登录外壳程序之间的区别?


317

我了解交互式外壳程序和非交互式外壳程序之间的基本区别。但是,将登录shell与非登录shell究竟有何区别呢?

您可以举非登录交互式外壳的使用示例吗?


45
我认为这个问题最好用“ 为什么 /我们应该区分登录和非登录外壳程序”来表述?在每个读取的启动文件方面,网络上的许多地方已经告诉我们有什么区别;但是他们似乎都没有一个令人满意且令人信服的方式回答“为什么”。您绝对不希望其中一种或另一种行为很好的示例用例。
Kal

2
@Kal这将是一个不同的问题,因为此处没有任何答案可以解决。编辑:实际上,这里是:为什么登录 Shell之上的登录 Shell?
Skippy le Grand Gourou

Answers:


304

登录外壳程序是您登录交互式会话时在您的用户ID下执行的第一个过程。登录过程告诉shell遵循以下约定:传递参数0(通常是shell可执行文件的名称),并带有一个-字符(例如-bash,通常为)bash。登录shell通常读取一个文件,该文件之类的设置环境变量:/etc/profile~/.profile为传统Bourne shell的,~/.bash_profile另外对于bash /etc/zprofile~/.zprofile为zsh的/etc/csh.login~/.login为CSH等。

当您在文本控制台上,通过SSH或通过进行登录时su -,将获得一个交互式登录外壳。当您以图形方式(在X显示管理器上)登录时,没有登录外壳,而是获得了会话管理器或窗口管理器。

很少运行非交互式登录外壳,但是当您使用显示管理器登录时,一些X设置会这样做,以安排读取配置文件。其他设置(取决于发行版和显示管理器)可以读取/etc/profile~/.profile显式读取,也可以不读取。获取非交互式登录外壳的另一种方法是使用通过标准输入(不是终端)传递的命令远程登录ssh example.com <my-script-which-is-stored-locally(例如ssh example.com my-script-which-is-on-the-remote-machine,与运行非交互式非登录外壳的相对,)。

在现有会话的终端(屏幕,X终端,Emacs终端缓冲区,另一个终端中的外壳等)中启动外壳时,您将获得一个交互式非登录外壳。该外壳可能会读出壳配置文件(~/.bashrc对于bash援引为bash/etc/zshrc~/.zshrc用于zsh的,/etc/csh.cshrc~/.cshrc用于CSH,该文件通过指定ENV对POSIX / XSI兼容外壳,例如仪表板,KSH,和bash可变时作为调用sh$ENV如果设置和~/.mkshrc用于mksh等)。

当外壳程序运行脚本或通过其命令行传递的命令时,它是一个非交互式,非登录外壳程序。这样的shell一直在运行:当一个程序调用另一个程序时,它实际上在shell中运行一个很小的脚本来调用另一个程序是很常见的。在这种情况下,某些shell会读取启动文件(bash运行BASH_ENV变量指示的文件,zsh运行/etc/zshenvand ~/.zshenv),但这是有风险的:可以在各种上下文中调用该shell,几乎没有什么可以做的打破一些东西。

我正在简化一下,有关详细信息,请参阅手册。


2
您能否举个例子,说明如何bash作为非交互式登录外壳运行?
Piotr Dobrogost

13
@PiotrDobrogostecho $- | bash -lx
Gilles

1
我不知道这通常是否正确,但是我想指出的是,当我打开新终端(使用默认设置在osx上)时,即使没有输入用户名或密码,我也会得到一个登录shell。
凯文·惠勒

4
@KevinWheeler默认情况下,在OSX上,终端应用程序运行登录外壳程序。(正如我所解释的那样,启动外壳程序的程序将决定该外壳程序是否充当登录外壳程序。)这不是正常的处理方式。
吉尔斯2015年

2
@IAmJulianAcosta如果FOO是环境变量(即.profile包含export FOO=something),则它可用于所有子流程,包括foo.sh。如果更改.profileexport FOO=something_else,然后./foo.sh将继续打印something,直到下一次你登录。
吉尔斯

48

告诉您是否在登录shell中:

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.

在Bash中,您还可以使用shopt login_shell

prompt> shopt login_shell
login_shell     off

(或on在登录shell中)。

可以在man bash(搜索调用)中找到信息。这是节选:

登录外壳是一个参数为零的第一个字符为-的外壳程序,或以--login选项开头的外壳程序。

您可以自己测试。每次使用SSH时,您都在使用登录Shell。例如:

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

使用登录Shell的重要性在于/home/user/.bash_profile将执行其中的所有设置。如果您有兴趣,可以从这里获得更多信息(来自man bash

“当bash作为交互式登录shell或具有--login选项的非交互式shell被调用时,它首先从文件/ etc / profile中读取并执行命令(如果该文件存在的话)。读取该文件后,它将查找~/.bash_profile~/.bash_login~/.profile以该顺序,并且读取和执行从存在并且是可读的。当外壳被启动以抑制这种行为可以使用的--noprofile选项的第一个命令“。


23

在登录外壳中,argv[0][0] == '-'。这就是它知道它是登录shell的方式。

然后在某些情况下,其行为取决于其“登录外壳”状态。例如,不是登录外壳的外壳将不会执行“注销”命令。


4
根据,还要man bash特别强调:“登录外壳是其参数为零的第一个字符是-的登录外壳,或者以--login选项开头的登录外壳
通配符

18

在GUI的新终端中启动的外壳将是交互式非登录外壳。例如,它将提供您的.bashrc,而不是您的.profile。


4

我将详细介绍Gilles的出色答案,并结合Timothy的方法来检查登录shell类型。

如果您想自己看看事物,请尝试以下片段和场景。

检查外壳是否(非)交互式

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

检查外壳是否(非)登录

如果输出的echo $0开头为-,则为登录外壳程序(echo $0输出示例:)-bash。否则,它是非登录shell(echo $0输出示例:)bash

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

让我们将上面的两个结合在一起,一次获得两个信息:

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"

场景:

没有特殊选项的典型SSH会话

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

通过新shell运行脚本或显式执行

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

远程运行本地脚本

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

远程通过SSH运行命令

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

使用-tSwitch 通过SSH远程运行命令

要使用ssh通过ssh远程运行命令时,可以显式请求交互式shell -t

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

注意:关于为何远程运行命令的主题不在此处,login shell更多信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.