bash初始化文件详解
目录
本文使用的环境: Bash 4.2.46
bash启动时会执行一系列脚本, 具体要执行哪些启动文件, 这和bash的类型有关: 是否为交互式(interactive)的shell, 是否为登录式(login)的shell
1. 交互式shell/非交互式shell
1.1 如何启动一个交互式shell/非交互式shell
- 日常使用ssh登录的shell是交互式shell
- 图形化界面下打开的terminal也是交互式shell
- 通过
bash script.sh
或./script.sh
执行脚本时, 会创建一个子shell来执行此脚本, 此时的子shell为非交互式shell - 通过ssh远程执行命令的shell为非交互式shell
1.2 如何判断是否为交互式shell
$-
会输出set设置的一些选项, 输出结果结果中的i
表示interactive(但不能通过set设置是否为交互式)
# 脚本中判断是否为交互式shell case "$-" in *i*) echo 'This shell is interactive' ;; *) echo 'This shell is not interactive' ;; esac
# 此时为交互式shell $ echo $- himBHs # 执行脚本时创建的子shell为非交互式shell $ cat script.sh echo "$-" $ bash script.sh hB
在非交互式shell不会设置PS1, 所以通过PS1是否有值判断也是可行的
if [ -z "$PS1" ]; then echo 'This shell is not interactive' else echo 'This shell is interactive' fi
2. 登录式shell/非登录式shell
2.1 如何启动一个登录式shell/非登录式shell
- 通过
bash -l
或su -l
命令启动的为登录式shell - 通过ssh登录的shell为登录式shell
- 通过ssh远程执行命令的shell为非登录式shell
- 图形化界面下启动的"terminal"默认为非登录式的, 但是可以更改为登录式shell
2.2 如何判断是否为登录式shell
可通过shopt
命令来查看是否为登录式shell, 也可以通过此命令来转换登录式/非登录式shell
$ shopt login_shell login_shell off
3. 启动文件
了解了什么是交互式/登录式shell之后, 我们来看下这4种情况下shell的初始化文件
3.1 测试方法
涉及到的文件主要有: /etc/profile, ~/.profile, ~/.bash_profile, ~/.bash_login, ~/.bashrc
将echo [/etc/profile]
添加到/etc/profile的第一行(其他文件同理), 根据每次登录服务器时的输出就能看到哪些文件被执行了
3.2 交互登录shell
交互登录式shell初始化的文件为:
- /etc/profile
- ~/.bash_profile, ~/.bash_login, and ~/.profile 这三个文件只会执行其中一个, 找到其中一个别的就不执行了, 优先级从前往后递减
通过ssh的方式登录即可得到交互登录式shell
$ ssh wbourne@192.168.0.101 [/etc/profile] [~/.bash_profile] [~/.bashrc]
再来验证~/.bash_profile, ~/.bash_login, and ~/.profile这三个文件的优先级
将~/.bash_profile改名为~/.bash_profile.bak, 再次登录服务器, 可以看到, ~/.bash_profile没有被执行, 取而代之的是~/.bash_login
$ ssh wbourne@192.168.0.101 [/etc/profile] [~/.bash_login]
执行完成之后, 为了不影响后续测试, ~/.bash_profile.bak改回~/.bash_profile
3.3 交互非登录shell
交互非登录式shell初始化的文件为:
- ~/.bashrc
通过su
命令切换用户即可得到交互非登录式shell
$ ssh root@192.168.0.101 $ su wbourne [~/.bashrc]
通过su
切换用户后, 按下Tab键发现自动补全用不了, 是因为/etc/profile中有以下一段脚本, 而自动补全与/etc/profile.d中的脚本有关
可以将这一段添加到~/.bashrc文件中, 就可以使交互式shell都能够自动补全, 至于为什么, 会在4.2 ~/.bashrc中讲到
if [ -d /etc/profile.d ]; then for i in /etc/profile.d/*.sh; do if [ -r $i ]; then . $i fi done unset i fi
3.4 非交互非登录shell
非交互非登录式shell初始化的文件为:
- 查找
$BASH_ENV
变量并执行, 就像if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
一样
bash xxx.sh
所创建用来执行脚本的子shell为非登录非交互式shell
# 登录服务器时的shell是交互登录式shell $ ssh wbourne@192.168.0.101 [/etc/profile] [~/.bash_profile] [~/.bashrc] # 编写一个脚本并执行, 执行脚本时创建的子shell才是非交互非登录shell # 此处只有脚本本身的输出, 没有任何初始化文件被执行 $ cat script.sh echo "$-" echo "$BASH_ENV" shopt login_shell $ bash script.sh hB login_shell off
设置$BASH_ENV
变量, 再次测试, 可以看到, ~/.bashrc被执行
$ export BASH_ENV='~/.bashrc' $ bash script.sh [~/.bashrc] hB ~/.bashrc login_shell off
测试完之后执行unset BASH_ENV
删除BASH_ENV变量, 以免影响带后续测试
3.5 非交互登录shell
非交互登录式shell初始化的文件为:
- /etc/profile
- ~/.bash_profile, ~/.bash_login, and ~/.profile 同上, 三取其一
- 查找
$BASH_ENV
变量并执行, 就像if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
一样
在bash xxx.sh
的基础上加上-l
选项可得到登录非交互式shell
$ cat script.sh echo "$-" echo "$BASH_ENV" shopt login_shell $ bash -l script.sh [/etc/profile] [~/.bash_profile] [~/.bashrc] hB login_shell on
再验证下$BASH_ENV
. 注意, .bashrc输出了两次, 4.2 ~/.bashrc会讲到为什么
$ export BASH_ENV='~/.bashrc' $ bash -l script.sh [/etc/profile] [~/.bash_profile] [~/.bashrc] [~/.bashrc] hB ~/.bashrc login_shell on
4. 其他
4.1 /etc/bash.bashrc与/etc/bashrc
大部分发行版还会涉及/etc/bash.bashrc与/etc/bashrc这两个文件, 例如Ubuntu 18.04 Desktop的/etc/profile文件中有. /etc/bash.bashrc
的语句, CentOS 7 Server的~/.bashrc文件中有. /etc/bashrc
的语句
4.2 ~/.bashrc
上述例子中, 只有交互非登录shell才会调用~/.bashrc, 但是其他例子的输出也包含了~/.bashrc, 甚至有的执行了两次, 这是因为:
一般的发行版中, ~/.profile文件中一般都有. ~/.bashrc
的语句, 以此来保证无论是登录式shell还是非登录式shell, ~/.bashrc都会被执行. 换句话说, 只要是交互式shell, ~/.bashrc都会被执行
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通