前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shell 编程(3)-bash 配置文件

Shell 编程(3)-bash 配置文件

原创
作者头像
懒人的小脑
修改2019-01-28 09:43:03
1.4K0
修改2019-01-28 09:43:03
举报

用户登录系统时,bash 会进行一系列操作,如加载各种 bash 配置文件,设置或清空一些列的变量,有时还会执行一些自定义的命令。

有些时候登录系统时可以交互的,如正常登录系统,有些时候时无交互的,如执行一个脚本。bash 启动类型分为交互式 shell 和非交互式 shell。交互式 shell 还分为交互式的登录 shell 和交互式的非登录 shell。

非交互式 shell 在某些时候可以在 bash 的 命令后面带上“--login|-l”,这样是非交互式的登录式 shell。

判断交互式和登录式shell

交互式 shell

交互式模式就是在终端上执行,shell等待你的输入,并且立即执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、退出。当你退出后,shell也终止了。

非交互式模式,以shell script(非交互)方式执行。在这种模式 下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾EOF,shell也就终止了。

判断交互式shell

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

代码语言:txt
复制
echo $-
himBH

vim a.sh
#! /bin/bash
echo $-

bash a.sh
hB

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

代码语言:txt
复制
[root@localhost ~]# echo $PS1
[\u@\h \W]\$

登录式 shell

登录式shell需要用户名、密码登录后才能进入的shell(或者通过"--login"选项生成的shell)。

非登录shell不需要输入用户名和密码即可打开的Shell,例如:直接命令“bash”就是打开一个新的非登录shell,在Gnome或KDE中打开一个“终端”(terminal)窗口程序也是一个非登录shell。

执行exit命令,退出一个shell(登录或非登录shell);

执行logout命令,退出登录shell(不能退出非登录shell)。

bash是 login shell时,其进程名为"-bash"而不是bash。

man bash: A login shell is one whose first character of argument zero is a -, or one started with the --login option.

代码语言:txt
复制
# 在 login shell 中
[root@localhost ~]# echo $0
-bash
[root@localhost ~]# ps -ef | grep '\-bash' | grep -v grep
root     11338 11337  0 08:17 pts/0    00:00:00 -bash

#在非登录式 shell 中
[simon@localhost ~]$ echo $0
bash
[simon@localhost ~]$ ps -ef | grep '\-bash' | grep -v grep

判断登录式

shopt login\_shell,值为 on 为登录式,否则为非登录式。

代码语言:txt
复制
[root@localhost ~]# shopt login_shell
login_shell    	on
[root@localhost ~]# bash
login_shell    	off

判断交互式和登录式的情况,一句话命令:

代码语言:txt
复制
[root@localhost ~]# echo $PS1;shopt login_shell

[root@localhost ~]# echo $-;shopt login_shell

分析几种 bash 的启动方式

正常登录

伪终端登录,如 ssh 登录,或虚拟终端登录时,为交互式登录 shell

代码语言:txt
复制
[root@localhost ~]# echo $PS1;shopt login_shell 
[\u@\h \W]\$
login_shell     on

su 命令

执行 su 命令不带"--login"时为交互式非登录shell,带“--login”时,为交互式登录 shell。

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

代码语言:txt
复制
[root@localhost ~]# su root

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

[root@localhost ~]# su -
Last login: Sat Aug 19 13:24:11 CST 2017 on pts/0

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

[root@localhsot ~]# bash

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

[root@localhost ~]# bash -l

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

命令组合

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

代码语言:txt
复制
[root@localhost ~]# (echo $BASH_SUBSHELL;echo $PS1;shopt login_shell)
1
[\u@\h \W]\$
login_shell     on

[root@localhost ~]# su

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

ssh 执行的远程命令

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

代码语言:txt
复制
[root@localhost ~]# ssh localhost 'echo $PS1;shopt login_shell'
 
login_shell     off

Shell 脚本

执行 shell 脚本时,为非交互、非登录式 shell。执行--login 时,为非交互、登录式 shell。

代码语言:txt
复制
[root@localhost ~]# vim b.sh
#!/bin/bash
echo $PS1
shopt login_shell

[root@localhost ~]# bash b.sh
 
login_shell     off

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

图像界面终端

在图形界面下打开终端时,为交互式、非登录式 shell。不过可以在设置中设置为 login shell。

bash 环境配置文件的加载顺序

bash环境配置主要是通过加载bash环境配置文件来完成。根据shell是否交互、是否登陆,将会影响加载的配置文件,除了交互登录属性,有些特殊的属性也会影响读取配置文件。

bash 的环境配置文件主要有

  • /etc/profile
  • ~/.bash_profile
  • ~/.bashrc
  • /etc/bashrc
  • /etc/profile.d/*.sh

为了测试各种情况读取哪些配置文件,先分别向几个配置文件中写入echo语句,用以判断该配置文件是否在启动bash时被读取加载。

代码语言:javascript
复制
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”选项

bash 启动时,将先读取/etc/profile,在依次搜索~/.bash_profile、~/.bash_login和~/.profile,并仅加载第一个搜索到且可读的文件。当退出时,将执行~/.bash_logout中的命令。

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

代码语言:shell
复制
grep -A 8 \*\.sh /etc/profile
 
for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then # 将"$-"从左向右模式匹配"*i"并将匹配到的内容删除(即进行变量切分),如果"$-"切分后的值不等于"$-",则意味着是交互式shell
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

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

代码语言:javascript
复制
grep -A 1 \~/\.bashrc ~/.bash_profile

if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

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

代码语言:javascript
复制
grep -A 1 /etc/bashrc ~/.bashrc

if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

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

代码语言: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
...
fii

交互式的登录 shell 加载 bash 环境配置文件的实际过程如下:

交互式登录 shell 的配置文件加载过程
交互式登录 shell 的配置文件加载过程

验证:

新开终端登录时:

代码语言:javascript
复制
Last login: Sat Jan 26 08:32:46 2019
/etc/profile.d/test.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes

ssh 远程登录时:

代码语言:javascript
复制
ssh localhost
Last login: Sat Jan 26 09:58:20 2019 from 192.168.1.110
/etc/profile.d/test.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes

执行带有“--login”选项的 login:

代码语言:javascript
复制
bash -l
/etc/profile.d/test.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes

su 带上“--login”时:

代码语言:javascript
复制
[root@localhost ~]# su -
上一次登录:六 1月 26 10:00:10 CST 2019从 localhostpts/2 上
/etc/profile.d/test.sh goes
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes

执行 shell 脚本时,带有"--login"时:

代码语言:javascript
复制
vim a.sh
#!/bin/bash --login
echo $-
echo Yeah
 
[root@localhost ~]# ./a.sh
/etc/profile goes
/etc/bashrc goes
~/.bashrc goes
~/.bash_profile goes
hB
Yeah

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

总结一下:

交互式非登录 shell

读取~/.bashrc,不会读取/etc/profile 和~/.bash_profile、~/.bash_login和~/.profile

交互式非登录 shell 的配置文件加载过程
交互式非登录 shell 的配置文件加载过程

验证:

代码语言:javascript
复制
[root@localhost ~]# bash
/etc/profile.d/test.sh goes
/etc/bashrc goes
~/.bashrc goes
代码语言:javascript
复制
[root@localhost ~]# su
/etc/profile.d/test.sh goes
/etc/bashrc goes
~/.bashrc goes

非交互非登录式 shell

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

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

远程 shell 启动 bash

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

代码语言:javascript
复制
[root@localhost ~]# ssh localhost echo hahaha
root@localhost's password:
/etc/bashrc goes
~/.bashrc goes
hahaha

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

总结一下

我们可以把bash配置文件分为两种,一种是全局配置文件,一种是在用户家目录的个人配置文件。

profile 类文件的作用:定义环境变量、运行命令或脚本

bashrc 类文件的作用:定义本地变量和函数、命令别名

先加载的配置文件的配置,可能会被后加载的配置所覆盖。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 判断交互式和登录式shell
    • 交互式 shell
      • 判断交互式shell
        • 登录式 shell
          • 判断登录式
          • 分析几种 bash 的启动方式
            • 正常登录
              • su 命令
                • 命令组合
                  • ssh 执行的远程命令
                    • Shell 脚本
                      • 图像界面终端
                      • bash 环境配置文件的加载顺序
                        • ①交互式登录 shell 或非登录式但带有“--login|-l”选项
                          • 交互式非登录 shell
                            • 非交互非登录式 shell
                              • 远程 shell 启动 bash
                              • 总结一下
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档