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

能否举一些使用非登录交互式shell的示例?

评论

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

@Kal这将是一个不同的问题,因为此处没有任何答案可以解决。编辑:实际上,这是:为什么在非登录shell上登录登录shell ?。

#1 楼

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

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

很少会运行非交互式登录外壳,但是当您使用显示管理器登录时,一些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终端缓冲区,一个外壳,例如另一个外壳等)中,您将获得一个交互式非登录外壳。该外壳程序可能会读取外壳程序配置文件(对于bash而言,~/.bashrc称为bash;对于zsh而言,/etc/zshrc~/.zshrc;对于csh而言,/etc/csh.cshrc~/.cshrc;对于POSIX / XSI兼容外壳,例如dash,ksh和bash,由ENV变量指示的文件当作为sh调用时(如果设置了$ENV,对于mksh等调用了~/.mkshrc)。

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

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

评论


您能举个例子如何将bash作为非交互式登录shell运行吗?

–彼得·多布罗格斯特(Piotr Dobrogost)
13年6月16日在8:47

@PiotrDobrogost echo $-| bash -lx

–吉尔斯'所以-不再是邪恶的'
13年6月16日在12:11

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

–凯文·惠勒
15年8月28日在22:55

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

–吉尔斯'所以-不再是邪恶的'
2015年8月28日23:01

@IAmJulianAcosta如果FOO是环境变量(即.profile包含export FOO = something),则它可用于所有子进程,包括foo.sh。如果将.profile更改为导出FOO = something_else,则./foo.sh仍将打印某些内容,直到您下次登录为止。

–吉尔斯'所以-不再是邪恶的'
16-10-6在15:13

#2 楼

告诉您是否在登录外壳中:

prompt> echo 
prompt> shopt login_shell
login_shell     off
-bash # "-" is the first character. Therefore, this is a login shell. prompt> echo
prompt> ssh user@localhost
user@localhost's password:
prompt> echo q4312078q
-bash
bash # "-" is NOT the first character. This is NOT a login shell.


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

q4312078q

(或登录外壳中的on)。

信息可在man bash(搜索调用)中找到。以下是摘录:


登录shell是一个登录shell,其参数零的第一个字符是-,或者
以--login选项开头。


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

q4312078q

使用登录shell的重要性在于,将执行/home/user/.bash_profile中的所有设置。如果您有兴趣,这里还有一些其他信息(来自man bash


“当bash作为交互式登录shell或作为与
非交互式shell一起调用时, --login选项,它首先从文件/ etc / profile中读取并
执行命令,如果该文件存在。
读取该文件后,它将查找~/.bash_profile
~/.bash_login~/.profile ,然后按顺序从第一个存在且可读的命令中读取并执行命令。启动外壳程序以禁止此行为时,可以使用
--noprofile选项。“


评论


从bash手册来看,登录shell是一个参数为零的第一个字符为'-'或使用--login选项调用的登录shell。根据此定义,echo $ 0不能确定shell是在登录shell中还是在登录shell中。并不是因为当我们使用bash --login启动shell时,$ 0被设置为bash(用于调用Bash的文件名),而不是-bash。

– jinbeom hong
7月8日19:29



#3 楼

在登录外壳程序中,为argv[0][0] == '-'
这就是它所知道的是登录外壳程序。

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

评论


据man bash强调,“登录shell是一个参数为零的第一个字符是-或以--login选项开头的登录shell。”

–通配符
17年1月23日在11:49

#4 楼

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

#5 楼

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

如果您想自己看看事物,请尝试下面的摘要和场景。

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

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


检查外壳是否(非)登录

如果echo -的输出以echo -bash开头,则为登录外壳(echo bash输出示例:-t)。否则,它是非登录外壳程序(-t输出示例:login shell)。
if echo 
THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; 
THIS_SHELL_LOGIN_TYPE='non-login'; 
if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; 
if echo 
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 
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 
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
| 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
| 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
| grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"
| grep -e ^\- 2>&1>/dev/null; then echo "This is login shell."; else echo "This is non-login shell."; fi;


方案:

没有特殊选项的典型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 
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 q4312078q | 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
| 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


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

q4312078q

远程运行本地脚本

q4312078q

通过ssh远程运行命令
/>
q4312078q

使用q4312079q开关在ssh上远程运行命令

当您要使用qsh通过ssh远程运行命令时,可以显式请求交互式shell。开关。

q4312078q

注意:关于为什么远程运行命令不是q4312079q的更多信息,请参见此处。

#6 楼

这是旧线程,但是我刚刚找到了非登录交互式shell的具体示例。

当我在Linux VM上使用VSCode进行远程开发时,我意识到/etc/profile.d/env_file.sh中的环境变量不是甚至在重新标记VSCode和终端本身之后,也由VSCode集成终端拾取。 /bin/bash的输出表明它不是登录外壳。

,连接到远程Linux机器后,VSCode似乎只是启动了一个主登录外壳,但是对于每个集成终端,它仅启动了另一个ps处理。您会看到-的输出没有-bash,但是不能确定当前外壳程序是否已登录。

$ echo 
~$ echo 
$ echo q4312078q
/bin/bash
$ ps  $(echo $$)
   PID TTY      STAT   TIME COMMAND
  2309 pts/3    Ss     0:00 /bin/bash -l
-bash ~$ ps $(echo $$) PID TTY STAT TIME COMMAND 2088 pts/2 Ss 0:00 -bash
/bin/bash $ ps $(echo $$) PID TTY STAT TIME COMMAND 2274 pts/3 Ss 0:00 /bin/bash


当我登录服务器时直接通过SSH,我看到-l,这是一个登录shell。

q4312078q

然后我在VSCode中添加了shell参数($$)选项。现在,回声/bin/bash的输出是相同的,但请注意-l(当前进程的ID,PID)--login带有echo ps $(echo $$)-bash)选项。

q4312078q

因此,要检查外壳程序是否为登录外壳程序,需要同时检查/bin/bash -l和q4312079q。根据实现的不同,输出应为q4312079q或q4312079q