当你打开终端或登录 Linux 系统时,Bash 会从一组启动文件中读取并执行命令。这些文件让你可以自定义 shell 环境:创建别名、向 $PATH 添加目录、设置环境变量以及更改 shell 提示符。

Bash 读取哪个启动文件取决于 shell 是登录 shell 还是非登录 shell。本指南解释了 .bashrc 和 .bash_profile 之间的区别、每个文件的加载时机,以及应将自定义设置放在何处。

交互式与非交互式 Shell

Shell 可以是交互式的,也可以是非交互式的:

  • 交互式 shell - 从用户读取输入并将输出写入终端的 shell。这就是你在提示符下输入命令时使用的 shell。
  • 非交互式 shell - 在没有用户交互的情况下运行的 shell,例如执行 Bash 脚本时。非交互式 shell 不读取 .bashrc 或 .bash_profile,但通过 SSH 运行命令时有一个例外,将在下面介绍。

登录与非登录 Shell

交互式 shell 可以是登录 shell,也可以是非登录 shell:

  • 登录 shell - 在你登录系统时调用。这包括通过 SSH 登录、在本地控制台登录,或使用 --login 选项启动 Bash。
  • 非登录 shell - 在图形桌面中打开新终端窗口或选项卡时调用,或在现有 shell 中输入 bash 时调用。

你可以通过运行以下命令来检查当前 shell 是否为登录 shell:

终端
shopt login_shell

如果输出是 login_shell on,则为登录 shell。如果是 login_shell off,则为非登录 shell。

启动文件加载顺序

当 Bash 作为交互式登录 shell启动时,它会按顺序读取以下文件:

  1. /etc/profile - 系统级设置。此文件通常会从 /etc/profile.d/ 目录中引用脚本。
  2. ~/.bash_profile - 用户特定的登录设置。如果此文件不存在,Bash 会查找 ~/.bash_login,然后是 ~/.profile,并执行它找到的第一个文件中的命令。

当登录 shell 退出时,Bash 会读取并执行 ~/.bash_logout(如果存在)中的命令。这是放置清理命令的地方,例如清屏或删除临时文件。

当 Bash 作为交互式非登录 shell启动时,它会读取:

  1. /etc/bash.bashrc - Debian 和 Ubuntu 上交互式 shell 的系统级设置。这些发行版对 Bash 进行了修补以读取此文件,这不是上游 Bash 的行为。Fedora 和 RHEL 使用 /etc/bashrc,该文件由默认的 ~/.bashrc 引用,而不是由 Bash 本身读取。
  2. ~/.bashrc - 用户特定的 shell 设置。

下表总结了每种场景下读取哪些文件:

Shell 类型读取的文件
交互式登录(SSH、控制台、bash --login)/etc/profile → ~/.bash_profile(或 ~/.bash_login 或 ~/.profile)
交互式非登录(新终端选项卡、输入 bash)Debian/Ubuntu:/etc/bash.bashrc → ~/.bashrc;Fedora/RHEL:~/.bashrc → /etc/bashrc
非交互式(脚本)无(除非设置了 BASH_ENV)
通过 SSH 的非交互式(ssh host command)~/.bashrc

.bashrc 与 .bash_profile 的区别

.bash_profile 在每次登录 shell 时执行。.bashrc 在交互式非登录 shell 以及由远程 shell 守护进程启动的某些非交互式 Bash 会话中执行。

实际上,大多数用户希望他们的交互式自定义设置在登录和非登录 Bash shell 中都可用。标准做法是将这些自定义设置放在 ~/.bashrc 中,并让 ~/.bash_profile 引用它:

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

通过此设置,交互式登录和非登录 Bash shell 会加载相同的配置。

什么内容放在哪里

自定义项文件原因
别名~/.bashrc在每个交互式 shell 中均可用
Shell 函数~/.bashrc在每个交互式 shell 中均可用
提示符自定义(PS1)~/.bashrc应用于每个新 shell
$PATH 修改~/.bash_profile 或 ~/.profile为登录会话设置,并由其子进程继承
环境变量(export)~/.bash_profile 或 ~/.profile对从登录会话启动的程序可用
登录时运行一次的命令~/.bash_profile仅在登录期间运行(例如 ssh-agent、启动消息)

.profile 与 .bash_profile

许多 Linux 发行版使用 ~/.profile 而不是 ~/.bash_profile。区别在于:

  • ~/.bash_profile - 仅由 Bash 读取。
  • ~/.profile - 由 Bash 和其他 POSIX 兼容 shell(sh、dash)读取。

如果 ~/.bash_profile 和 ~/.profile 都存在,Bash 只读取 ~/.bash_profile 并忽略 ~/.profile。如果你希望读取 ~/.profile,要么删除 ~/.bash_profile,要么在其中引用 ~/.profile。

Ubuntu 和 Debian 默认创建 ~/.profile,不创建 ~/.bash_profile。Fedora 和 RHEL 创建 ~/.bash_profile。

macOS 注意事项

在 macOS 上,Terminal.app 和 iTerm2 默认打开登录 shell,这与大多数 Linux 终端模拟器相反。这意味着在 macOS 上每次打开终端窗口时,都会读取 ~/.bash_profile(对于 zsh 则为 ~/.zprofile)。

自 macOS Catalina(2019 年)起,macOS 的默认 shell 是 zsh,而不是 Bash。zsh 的对应文件为:

Bash 文件Zsh 对应文件
~/.bash_profile~/.zprofile
~/.bashrc~/.zshrc

如果这些启动文件中的任何一个在你的系统上不存在,你可以创建它们。

快速参考

如需可打印的快速参考,请参阅 Bash 速查表。

文件加载时机用途
/etc/profile登录 shell系统级环境设置
~/.bash_profile登录 shell用户登录设置,引用 .bashrc
~/.profile登录 shell(如果没有 .bash_profile)可移植的用户登录设置
~/.bashrc交互式非登录 shell 以及由远程 shell 守护进程启动的非交互式 Bash别名、函数、提示符以及放置在交互性保护之前的远程命令设置
/etc/bash.bashrc(Debian/Ubuntu)或 /etc/bashrc(Fedora/RHEL)非登录交互式 shell系统级 shell 设置
~/.bash_logout登录 shell 退出注销时运行的清理命令

故障排除

通过 SSH 连接时别名不起作用
SSH 打开的是一个登录 shell,它读取 ~/.bash_profile,但不读取 ~/.bashrc。在你的 ~/.bash_profile 中添加 . ~/.bashrc,这样别名也会在登录 shell 中加载。

远程 SSH 命令找不到程序
ssh user@host 打开一个交互式登录 shell,它读取 ~/.bash_profile。当用户的登录 shell 是 Bash 时,运行 ssh user@host 'command' 会启动一个非交互式 shell,它读取 ~/.bashrc。Debian 和 Ubuntu 上的默认 .bashrc 在文件顶部的交互性保护处返回,而 Fedora 和 RHEL 的默认版本则继续执行整个文件。如果远程命令在此保护的系统上需要 PATH 更改,请仅将必需的 export 语句放在保护之上,并将别名、提示符和其他交互式设置放在保护之下。

.bashrc 中的 PATH 更改未生效
将登录会话的 PATH 更改放在 ~/.bash_profile 或 ~/.profile 中。如果你有意在 ~/.bashrc 中保留仅交互式的 PATH 更改,请确保 ~/.bash_profile 引用该文件,以便交互式登录 shell 也能获得此更改。

.bashrc 的更改未生效
编辑 ~/.bashrc 后,要么打开一个新终端,要么运行 source ~/.bashrc 以在当前 shell 中应用更改。

同时存在 .bash_profile 和 .profile 时只会使用其中一个
如果 ~/.bash_profile 存在,Bash 就会忽略 ~/.profile。要么将所有设置合并到一个文件中,要么让 ~/.bash_profile 引用 ~/.profile。

常见问题解答

我应该编辑哪个文件来添加别名?
将别名添加到 ~/.bashrc。只要 ~/.bash_profile 引用了 ~/.bashrc,你的别名就会在交互式登录和非登录 shell 中可用。

为什么我的终端不读取 .bash_profile?
大多数 Linux 终端模拟器(GNOME 终端、Konsole、xfce4-terminal)打开的是非登录 shell,它们读取的是 ~/.bashrc 而不是 ~/.bash_profile。只有 SSH 会话、控制台登录和 bash --login 才会触发登录 shell。

source 和 . 有什么区别?
它们是等效的。两者都在当前 shell 中执行文件中的命令。. ~/.bashrc 和 source ~/.bashrc 执行相同的操作。. 语法符合 POSIX 规范,而 source 是 Bash 的扩展。

当我执行脚本时,.bashrc 会运行吗?
对于本地脚本不会。脚本在非交互式 shell 中运行,除非脚本显式地引用 ~/.bashrc 或设置了 BASH_ENV 变量指向它,否则不会读取 ~/.bashrc。有一个例外:当 Bash 检测到其标准输入连接到网络连接时(例如 ssh user@host 'command'),即使 shell 不是交互式的,它也会读取 ~/.bashrc。Debian 和 Ubuntu 在默认的 ~/.bashrc 顶部放置了以下交互性检查:

~/.bashrcsh
# 如果不是交互式运行,则不执行任何操作
case $- in
    *i*) ;;
      *) return;;
esac

我应该在哪里为 GUI 应用程序设置环境变量?
GUI 应用程序不会读取 .bashrc 或 .bash_profile。在基于 systemd 的系统上,将环境变量放在 ~/.config/environment.d/*.conf 中,或者在桌面环境设置中设置它们。