Bash启动时配置文件的加载过程

16 篇文章 2 订阅

当用户登录系统时,会加载各种bash配置文件,还会设置或清空一系列变量,有时还会执行一些自定义的命令。这些行为都算是启动bash时的过程。

另外,有些时候登录系统是可以交互的(如正常登录系统),有些时候是无交互的(如执行一个脚本),因此总的来说bash启动类型可分为交互式shell和非交互式shell。更细分一层,交互式shell还分为交互式的登录shell和交互式非登录shell,非交互的shell在某些时候可以在bash命令后带上"–login"或短选项"-l",这时也算是登录式,即非交互的登录式shell。

1.1 判断是否交互式、是否登录式

判断是否为交互式shell有两种简单的方法:

方法一:判断变量"-",如果值中含有字母"i",表示交互式。

[root@linuxidc~]# echo $-
himBH
[root@linuxidc~]# vim a.sh
#!/bin/bash
echo $-
[root@linuxidc~]# bash a.sh
hB

方法二:判断变量PS1,如果值非空,则为交互式,否则为非交互式,因为非交互式会清空该变量。

[root@linuxidc~]# echo $PS1
[\u@\h \W]\$

判断是否为登录式的方法也很简单,只需执行"shopt login"即可。值为"on"表示为登录式,否则为非登录式。

[root@linuxidc~]# shopt login_shell  
login_shell     on
[root@linuxidc~]# bash

[root@linuxidc~]# shopt login_shell
login_shell off

所以,要判断是交互式以及登录式的情况,可简单使用如下命令:

echo $PS1;shopt login_shell

或者

echo $-;shopt login_shell

1.2 几种常见的bash启动方式

(1).正常登录(伪终端登录如ssh登录,或虚拟终端登录)时,为交互式登录shell。

[root@linuxidc~]# echo $PS1;shopt login_shell 
[\u@\h \W]\$
login_shell     on

(2).su命令,不带"–login"时为交互式、非登录式shell,带有"–login"时,为交互式、登录式shell。

[root@linuxidc~]# su root
[root@linuxidc~]# echo $PS1;shopt login_shell 
[\u@\h \W]\$
login_shell     off
[root@linuxidc~]# su -
Last login: Sat Aug 19 13:24:11 CST 2017 on pts/0
[root@linuxidc~]# echo $PS1;shopt login_shell
[\u@\h \W]\$
login_shell     on

(3).执行不带"–login"选项的bash命令时为交互式、非登录式shell。但指定"–login"时,为交互式、登录式shell。

[root@linuxidc~]# bash
[root@linuxidc~]# echo $PS1;shopt login_shell
[\u@\h \W]\$
login_shell     off
[root@linuxidc~]# bash -l
[root@linuxidc~]# echo $PS1;shopt login_shell
[\u@\h \W]\$
login_shell     on

(4).使用命令组合(使用括号包围命令列表)以及命令替换进入子shell时,继承父shell的交互和登录属性。

[root@linuxidc~]# (echo $BASH_SUBSHELL;echo $PS1;shopt login_shell)
1
[\u@\h \W]\$
login_shell     on
[root@linuxidc~]# su
[root@linuxidc~]# (echo $BASH_SUBSHELL;echo $PS1;shopt login_shell)
1
[\u@\h \W]\$
login_shell     off

(5).ssh执行远程命令,但不登录时,为非交互、非登录式。

[root@linuxidc~]# ssh localhost 'echo $PS1;shopt login_shell'
login_shell     off

(6).执行shell脚本时,为非交互、非登录式shell。但指定了"–login"时,将为非交互、登录式shell。

例如,脚本内容如下:

[root@linuxidc~]# vim b.sh
#!/bin/bash
echo $PS1
shopt login_shell

不带"–login"选项时,为非交互、非登录式shell。

[root@linuxidc~]# bash b.sh

login_shell off

带"–login"选项时,为非交互、登录式shell。

[root@linuxidc~]# bash -l b.sh
login_shell     on

(7).在图形界面下打开终端时,为交互式、非登录式shell。
在这里插入图片描述

但可以设置为使用交互式、登录式shell。

在这里插入图片描述

1.3 加载bash环境配置文件

无论是否交互、是否登录,bash总要配置其运行环境。bash环境配置主要通过加载bash环境配置文件来完成。但是否交互、是否登录将会影响加载哪些配置文件,除了交互、登录属性,有些特殊的属性也会影响读取配置文件的方法。

bash环境配置文件主要有/etc/profile、~/.bash_profile、~/.bashrc、/etc/bashrc和/etc/profile.d/*.sh,为了测试各种情形读取哪些配置文件,先分别向这几个配置文件中写入几个echo语句,用以判断该配置文件是否在启动bash时被读取加载了。

echo "echo '/etc/profile goes'" >>/etc/_profile
echo "echo '~/.bash_profile goes'" >>~/.bash_profile
echo "echo '~/.bashrc goes'" >>~/.bashrc
echo "echo '/etc/bashrc goes'" >>/etc/bashrc
echo "echo '/etc/profile.d/test.sh goes'" >>/etc/profile.d/test.sh
chmod +x /etc/profile.d/test.sh

①.交互式登录shell或非交互式但带有"–login"(或短选项"-l",例如在shell脚本中指定"#!/bin/bash -l"时)的bash启动时,将先读取/etc/profile,再依次搜索~/.bash_profile、~/.bash_login和~/.profile,并仅加载第一个搜索到且可读的文件。当退出时,将执行~/.bash_logout中的命令。

但要注意,在/etc/profile中有一条加载/etc/profile.d/*.sh的语句,它会使用source加载/etc/profile.d/下所有可执行的sh后缀的脚本。

[root@linuxidc~]# grep -A 8 \*\.sh /etc/profile  
for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

内层if语句中的【"${-#*i}" != “$-”】表示将"$-“从左向右模式匹配”*i"并将匹配到的内容删除(即进行变量切分),如果"$-“切分后的值不等于”$-",则意味着是交互式shell,于是怎样怎样,否则怎样怎样。

同样的,在~/.bash_profile中也一样有加载~/.bashrc的命令。

[root@linuxidc~]# grep -A 1 \~/\.bashrc ~/.bash_profile
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

而~/.bashrc中又有加载/etc/bashrc的命令。

[root@linuxidc~]# grep -A 1 /etc/bashrc ~/.bashrc
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

其实/etc/bashrc中还有加载/etc/profile.d/*.sh的语句,但前提是非登录式shell时才会执行。以下是部分语句:

if ! shopt -q login_shell ; then   # We're not a login shell
...
    for i in /etc/profile.d/*.sh; do
        if [ -r "$i" ]; then
            if [ "$PS1" ]; then
                . "$i"
            else
                . "$i" >/dev/null 2>&1
            fi
        fi
    done
...
fi

从内层if语句和/etc/profile中对应的判断语句的作用是一致的,只不过判断方式不同,写法不同。

因此,交互式的登录shell加载bash环境配置文件的实际过程如下图
在这里插入图片描述

以下结果验证了结论:

Last login: Mon Aug 14 04:49:29 2017     # 新开终端登录时
/etc/profile.d/*.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes
 [root@linuxidc~]# ssh localhost        # ssh远程登录时
root@localhost's password:
Last login: Mon Aug 14 05:05:50 2017 from 172.16.10.1
/etc/profile.d/*.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes
[root@linuxidc~]# bash -l        # 执行带有"--login"选项的login时
/etc/profile.d/*.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes
[root@linuxidc~]# su -          # su带上"--login"时
/etc/profile.d/*.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes
[root@linuxidc~]# vim a.sh    # 执行shell脚本时带有"--login"时
#!/bin/bash -l
echo haha
[root@linuxidc~]# ./a.sh 
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes
haha

之所以执行shell脚本时没有显示执行/etc/profile.d/*.sh,是因为它是非交互式的,根据/etc/profile中的【if [ “${-#i}" != “$-” ]】判断,它将会把/etc/profile.d/.sh的执行结果重定向到/dev/null中。也就是说,即使是shell脚本(带”–login "选项),它也加载了所有bash环境配置文件。

②.交互式非登录shell的bash启动时,将读取~/.bashrc,不会读取/etc/profile和~/.bash_profile、~/.bash_login和~/.profile。

因此,交互式非登录shell加载bash环境配置文件的实际过程为下图内方框中所示(由/etc/bashrc加载/etc/profile.d/*.sh下的配置文件):

在这里插入图片描述

例如,执行不带"–login"的bash命令或su命令时。

[root@linuxidc~]# bash
/etc/profile.d/*.sh goes
/etc/bashrc goes
~/.bashrc goes
[root@linuxidc~]# su
/etc/profile.d/*.sh goes
/etc/bashrc goes
~/.bashrc goes

③.非交互式、非登录式shell启动bash时,不会加载前面所说的任何bash环境配置文件,但会搜索变量BASH_ENV,如果搜索到了,则加载其所指定的文件。但有并非所有非交互式、非登录式shell启动时都会如此,见情况④。

它就像是这样的语句:

if [ -n "$BASH_ENV" ];`then
    . "$BASH_ENV"
fi

几乎执行所有的shell脚本都不会特意带上"–login"选项,因此shell脚本不会加载任何bash环境配置文件,除非手动配置了变量BASH_ENV。

④.远程shell方式启动的bash,它虽然属于非交互、非登录式,但会加载~/.bashrc,所以还会加载/etc/bashrc,由于是非登录式,所以最终还会加载/etc/profile.d/*.sh,只不过因为是非交互式而使得执行的结果全部重定向到了/dev/null中。

如果了解rsync,就知道它有一种远程shell连接方式。所谓的远程shell方式,是指通过网络的方式启动bash并将bash的标准输出关联起来,就像它连接了一个远程的shell守护进程一样。一般由sshd实现这样的连接方式,老版的rshd也一样支持。

事实也确实如此,使用ssh连接但不登录远程主机时(例如只为了执行远程命令),就是远程shell的方式,但它却是非交互、非登录式的shell。

[root@linuxidc~]# ssh localhost echo haha
root@localhost's password:
/etc/bashrc goes
~/.bashrc goes
haha

正如上文所说,它同样加载了/etc/profile.d/*.sh,只不过/etc/bashrc中的if判断语句【if [ “$PS1” ]; then】使得非交互式的shell要将执行结果重定向到/dev/null中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux启动过程中涉及几个重要过程配置文件的执行过程如下: 1. BIOS/UEFI启动:当计算机开机,首先会执行计算机的基本输入输出系统(BIOS)或统一扩展固件接口(UEFI)来初始化硬件和引导程序。 2. 引导程序:引导程序(如GRUB)会读取配置文件(如grub.cfg)来确定可用的操作系统和内核位置。然后,它内核镜像到内存中。 3. 内核初始化:的内核镜像会执行初始化过程,其中包括设置内核参数、初始化设备驱动程序、挂文件系统等。 4. init进程启动:内核初始化后,它会启动第一个用户空间进程,即init进程。init进程的配置文件通常是/etc/inittab或/etc/init/rcS文件。 5. 系统运行级别:根据init进程的配置文件,系统会进入特定的运行级别(也称为运行模式或系统状态)。每个运行级别定义了一组要启动或停止的进程。 6. 启动脚本执行:在特定运行级别下,init进程会读取并执行与该运行级别相关的启动脚本。这些脚本通常存储在/etc/init.d/目录中,并且使用符号链接链接到/etc/rc.d/目录中。 7. 服务启动启动脚本负责启动系统服务(如网络服务、日志服务等)。这些脚本使用特定的配置文件(如/etc/sysconfig)来设置服务的参数。 8. 用户登录:一旦系统服务启动完成,init进程会等待用户登录。用户登录后,init进程会启动用户特定的会话进程(如bash)。 总体而言,Linux启动过程中的配置文件包括引导程序配置文件、内核参数、init进程配置文件、运行级别配置文件启动脚本。这些配置文件定义了系统启动的组件和执行的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值