.bashrc 与 .bash_profile 的区别

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

Bash 会读取哪个启动文件,取决于当前 shell 是登录 shell 还是非登录 shell。本指南将解释 .bashrc.bash_profile 的区别、每个文件在何时被加载,以及你的个性化配置应该放在哪里。

交互式与非交互式 Shell

shell 既可以是交互式,也可以是非交互式:

  • 交互式 shell:从用户读取输入并将输出写到终端的 shell。你在提示符下输入命令时使用的就是它。
  • 非交互式 shell:无需用户交互即可运行的 shell,例如执行 Bash 脚本时。非交互式 shell 不会读取 .bashrc.bash_profile,但有一个例外——通过 SSH 执行的命令(见下文)。

登录 Shell 与非登录 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 启动时,会按以下顺序读取这些文件:

  • /etc/profile:系统级设置。该文件通常会引用 /etc/profile.d/ 下的脚本。
  • ~/.bash_profile:用户级登录设置。如果该文件不存在,Bash 会依次查找 ~/.bash_login、再查找 ~/.profile,并执行找到的第一个文件中的命令。

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

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

  • /etc/bash.bashrc:Debian 与 Ubuntu 上交互式 shell 的系统级设置。这些发行版对 Bash 做了补丁,使其读取该文件,这并非上游 Bash 的默认行为。Fedora 与 RHEL 改用 /etc/bashrc,且它是由默认 ~/.bashrc 引用的,而非由 Bash 自身读取。
  • ~/.bashrc:用户级 shell 设置。

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

Shell 类型读取的文件
交互式登录 shell(SSH、控制台、bash --login/etc/profile~/.bash_profile(或 ~/.bash_login~/.profile
交互式非登录 shell(新终端标签页、输入 bashDebian/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 去引用(source)它:

if [ -f ~/.bashrc ]; then

    . ~/.bashrc

fi

采用这种写法后,交互式的登录 shell 与非登录 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 速查表(Bash cheatsheet)。

文件加载时机用途
/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 中。如果你有意将仅用于交互式环境的 PATH 修改保留在 ~/.bashrc,请务必让 ~/.bash_profile 引用该文件,使交互式登录 shell 也能获得它。

修改 .bashrc 后未生效——编辑 ~/.bashrc 后,要么打开一个新的终端,要么运行 source ~/.bashrc 在当前 shell 中使改动生效。

.bash_profile.profile 都存在但只有一个被使用——如果存在 ~/.bash_profile,Bash 会忽略 ~/.profile。要么把设置合并到同一个文件,要么让 ~/.bash_profile 引用 ~/.profile

常见问题(FAQ)

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

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

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

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

# If not running interactively, don't do anything

case $- in

    *i*) ;;

      *) return;;

esac

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

总结

.bash_profile 由登录 shell 读取,而 .bashrc 由交互式非登录 shell 以及部分远程非交互式 Bash 会话读取。将交互式个性化配置放进 ~/.bashrc,在 ~/.bash_profile 中引用它,并将登录环境相关的设置保留在 ~/.bash_profile~/.profile 中。