交互式登录shell
本文是上一篇文章[[TMOUT引起服务器断开连接解决方法]]的附带研究产物。
TMOUT环境变量在Bash Beginners Guide的解释如下:
If set to a value greater than zero, TMOUT is treated as the default timeout for the read built-in. In an interative shell, the value is interpreted as the number of seconds to wait for input after issuing the primary prompt when the shell is interactive. Bash terminates after that number of seconds if input does not arrive.
TMOUT设置首先对read
命令会产生影响,如果在指定时间内没有输入,Bash会退出read语句输入环境。
其次,TMOUT会对交互式(interactive)shell产生影响,如果主提示符(PS1
)出现后指定时间内没有输入,bash会结束。
$ TMOUT=10
$ read # 10秒内没有输入,退出read命令
# 再过10秒shell没有输入,bash退出
# timed out waiting for input: auto-logout
那么这里的interactive shell
指的是什么?
shell分类
shell是用户与操作系统内核交互的文本接口,当用户输入命令,操作系统会输出结果到屏幕上。可以将shell从两个维度进行分类,两个维度可以相互组合。具体分类如下:
interactive vs non-interactive
shell可以分为interactive(交互)和non-interactive(非交互)shell。
- 交互式shell:用户从键盘输入命令,屏幕上输出结果方式,"Read-Evaluate-Print-Loop" (REPL)执行流程。
- 非交互式shell:通过shell脚本执行方式将命令组合调用,不能假设用户会输入或者用户能看到输出。一般建议将结果重定向到log文件中。
login vs non-login
shell还可以分为login(登录)和non-login(非登录)shell。
- 登录shell:用户登录到系统时启动的shell,需要用户名和密码等验证授权信息。
- 非登录shell:用户登录后启动的其它shell。比如在X图形界面环境下打开终端启用的shell,不要求提供用户名和密码信息。
使用ps
查看进程信息时,如果发现bash
命令前面有一个-
,表明是登录shell。
$ ps aux |grep bash
user 4853 0.0 0.1 26224 6220 pts/2 Ss+ 17:49 0:00 -bash
查看shell类型方法
下面介绍如何查看shell的类型。
使用$-
环境变量可以查看是否是交互式shell,而shopt login_shell
可以查看是否是登录shell。
$ echo $-
himBHs # 其中i代表interactive
$ shopt login_shell
login_shell on
以上表明是交互式登录shell,我们可以执行bash
命令进入subshell查看此时的shell类型
$ bash
$ echo $-
himBHs # 仍然是交互式shell
$ shopt login_shell
login_shell off # 此时是非登录shell
当执行shell脚本时,shell类型变为了非交互非登录shell。
#!/bin/bash
echo $-
shopt login_shell
执行结果:
$ ./test_shell.sh
hB
login_shell off
可以看出执行shell脚本时是非交互式、非登录shell。
shell类型组合还剩下最后一种:非交互式登录shell。
echo 'echo $-; shopt login_shell' | ssh localhost
stty: standard input: Inappropriate ioctl for device
Pseudo-terminal will not be allocated because stdin is not a terminal.
Activate the web console with: systemctl enable --now cockpit.socket
himBH # 交互式
login_shell on # 登录
非交互式登录类型的shell在一些特定的场景中很有用,例如在系统启动时自动运行一些任务,或者在远程执行命令时不需要用户交互的情况下使用。
Bash启动文件
为何关心shell的类型呢?因为这和shell启动时读取执行哪些配置文件有关。
interactive login shell
当bash以交互式登录shell或者非交互式shell加上--login
选项调用,bash读取执行启动文件顺序:
/etc/profile
(系统级配置文件,应用于所有用户)~/.bash_profile
、~/.bash_login
、~/.profile
(执行第一个存在且可读文件,后面的文件不执行)
注: --noprofile
选项可用于禁止该行为。
同时,退出bash时会自动读入执行以下文件:
~/.bash_logout
/etc/bash.bash_logout
interactive non-login shell
当交互式非登录shell启动时,bash只执行~/.bashrc
文件。
注:--norc
选项阻止该行为,而--rcfile file
选项强制bash读入并执行指定的file文件,而不是默认的~/.bashrc
。
non-interactive shell
当bash非交互式启动时,比如运行shell脚本,会查找BASH_ENV
环境变量,如果值存在,展开变量值作为读入执行文件,相当于执行
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
测试验证
测试环境:Centos 8.4, BASH
在上述提到的每一个配置环境中添加类似的echo "execute XXXX"
,查看哪些文件打印了相应语句。
通过SSH登录到系统时,会自动输出如下信息到屏幕:
execute /etc/profile
execute ~/.bash_profile
execute ~/.bashrc
其中~/.bash_login
与 ~/.profile
没有执行,因为bash首先找到了~/.bash_profile
文件并执行。
执行~/.bashrc
文件的原因在于配置文件~/.bash_profile
中有如下命令:
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
当进入subshell时输出信息如下
$ bash
execute ~/.bashrc
如果仔细查看~/.bashrc
文件,会发现在一开始加载了/etc/bashrc
。
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
/etc/bashrc
是系统级配置文件,专门用于指定Bash配置信息,因为系统一般会提供多个shells。/etc/profile
配置文件可能也会被其它shell读取执行(比如sh),因此Bash特定语法命令最好放在/etc/bashrc
中防止其它shell加载时出现语法错误。
实际上,centos在交互式登录shell时真正读取的配置文件包括:
- /etc/profile
- ~/.bash_profile
- ~/.bashrc
- /etc/bashrc
小结
Bash处于何种状态(interactive/login)影响着Bash执行配置文件行为。当修改配置文件后未得到预料结果时需要查看Bash的状态。
参考资料
- https://unix.stackexchange.com/questions/50665/what-are-the-differences-between-interactive-non-interactive-login-and-non-lo
- https://www.baeldung.com/linux/interactive-non-interactive-login-non-login-shells
man bash
, "Invocation" section- https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_01.html
- https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
- https://copyprogramming.com/howto/new-tmux-sessions-do-not-source-bashrc-file