在Linux系统中,设置PATH变量有两种常见的方法:在/etc/environment文件或.profile文件中进行设置。 /etc/environment文件是全局环境变量文件,它适用于整个系统。通过在这个文件中添加路径,可以使所有用户都能够访问这些路径中的可执行文件。修改/etc/environment文件后,需要重新启动系统才能使更改生效。 另一种方法是在每个用户的.profile文件中设置PATH变量。.profile文件是用户登录时执行的脚本文件。通过在.profile文件中添加路径,只有该用户才能访问这些路径中的可执行文件。修改.profile文件后,需要重新登录或执行source命令使更改生效。 无论选择哪种方法,你都可以根据需要来设置PATH变量。在/etc/environment文件中设置的路径会对所有用户生效,而在.profile文件中设置的路径只对当前用户生效。

在哪里设置PATH环境变量最好?
是在~/.profile还是/etc/environment
PATH同时在这两个地方设置时,会出现什么情况? 最终的结果是这两个地方设置的值进行拼接吗?

最后一次分配给PATH的优先级当然是最高的。大多数脚本在脚本开始时都会明确设置它。 - AlexP
3请参阅https://help.ubuntu.com/community/EnvironmentVariables#Persistent_environment_variables。 - edwinksl
6个回答

摘要:

如果你想为当前用户的PATH变量添加一个路径(例如/your/additional/path),而不是为计算机上的所有用户添加,通常将其放在~/.profile的末尾,就像下面这两个例子中的一个一样:
PATH="/your/additional/path:$PATH"
PATH="$PATH:/your/additional/path"

请注意,路径的优先级从左到右递减,因此第一个路径具有最高优先级。如果你将路径添加到$PATH的左侧,它将具有最高优先级,并且该位置的可执行文件将覆盖其他所有文件。如果你将路径添加到右侧,它将具有最低优先级,并且来自其他位置的可执行文件将被优先选择。
然而,如果你需要为所有用户设置环境变量,我仍然不建议修改/etc/environment,而是在/etc/profile.d/中创建一个以.sh结尾的文件。 /etc/profile脚本和/etc/profile.d中的所有脚本都是每个用户个人~/.profile的全局等效物,并在其初始化期间由所有shell作为常规shell脚本执行。

更多细节:

  • /etc/environment 是一个系统范围的配置文件,这意味着它被所有用户使用。虽然它是由 root 拥有的,所以你需要成为管理员用户并使用 sudo 来修改它。

  • ~/.profile 是你自己用户的个人 shell 初始化脚本之一。每个用户都有一个,并且可以编辑自己的文件而不影响其他人。

  • /etc/profile/etc/profile.d/*.sh 是全局初始化脚本,相当于每个用户的 ~/.profile。全局脚本在用户特定脚本之前执行;主要的 /etc/profile 在退出之前执行 /etc/profile.d/ 中的所有 *.sh 脚本。


/etc/environment文件通常只包含以下一行内容: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
它为系统上的所有用户设置了PATH变量的默认值,不应该以重大方式更改。至少不要从中删除任何重要路径,如/bin、/sbin、/usr/bin和/usr/sbin。
此文件是每个用户的每个shell在最初配置文件中之一读取的。请注意,它不是一个shell脚本。它只是一个被某种方式解析的配置文件,只能包含环境变量赋值!
~/.profile文件可以包含许多内容,默认情况下,它包含了其他内容之外的检查,检查是否存在~/bin目录,并将其添加到用户现有的PATH变量中,如下所示(在旧版Ubuntu 16.04之前(无条件添加)和18.04上也添加了“~/.local/bin”):
# set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH" fi
你可以看到这里重新使用了旧的PATH值,并且新路径只是附加到开头,而不是覆盖所有内容。当你手动添加新路径时,你应该始终在新字符串中保留旧的$PATH值。
这个初始化脚本只由属于它的用户的shell读取,但还有另一个条件:
# ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists.
因此,如果你使用默认的Bash shell,你应该确保你没有~/.bash_profile或~/.bash_login文件,如果你希望~/.profile中的更改对你的用户生效。
要全面了解环境变量,请参阅: https://help.ubuntu.com/community/EnvironmentVariables
相关问题:bash.bashrc和/etc/environment文件之间的区别

2现在的~/.profile文件不再检查~/bin目录是否存在,而是直接添加了以下一行代码:PATH="$HOME/bin:$HOME/.local/bin:$PATH" - Gunnar Hjalmarsson
1@GunnarHjalmarsson 请解释一下"nowadays"的意思好吗?我正在使用16.04版本,那里的界面是这样的。 - Byte Commander
2在16.04版本中,/etc/skel/.profile文件包含了我提到的那一行。显然,你是在之前的版本中创建了你的用户。 - Gunnar Hjalmarsson
1@GunnarHjalmarsson 感谢提供的信息 - 直到大约五分钟前,我还以为默认的~/.profile仍然有这个设置,但你是对的 - 在我升级的16.04系统上,/etc/skel/.profile没有这个设置(在另一台机器上安装16.04时创建的用户帐户的.profile也没有它)。 - Eliah Kagan
2"...在它们的初始化过程中,所有的shell都会将其作为常规的shell脚本执行。我认为这可能会引起误解。对于一些人来说,这可能会暗示仅仅从GUI桌面打开一个非登录终端shell就会执行/etc/profile,但实际上并不会。" - Hawkeye Parker
小心,不是所有的东西都是一个交互式shell,所以有些东西不会加载任何.profile.bashrc,例如https://stackoverflow.com/a/18665363/516748。 - KCD
所以,如果你使用默认的Bash shell,你应该确保你没有一个/.bash_profile或者/.bash_login文件,如果你希望对你的用户生效的话,你可以在~/.profile中进行更改。我认为,删除.bash_profile和.bash_login可能不是一个更好的解决方案,而是利用它们来替代.profile文件。 - Tim M.
2你能详细说明一下为什么不编辑和扩展/etc/environment吗?它似乎就是为这个任务而设计的... - Marc

这个答案主要涉及在不同的配置文件中指定时,环境变量(比如PATH)被分配的顺序。我也会涵盖你通常应该设置它们的位置,但下面的列表并不按照你应该考虑使用它们的顺序列出。关于在Ubuntu中设置PATH和其他环境变量的一般信息,我还建议阅读EnvironmentVariables以及本问题的其他答案。
设置PATH的首选位置取决于你需要为哪些用户设置以及何时以及如何设置它。你的决策的一部分将是你是否想要设置一个适用于所有用户的环境变量,还是仅适用于每个用户。如果你不确定,我建议只为一个用户(例如你自己的账户)设置它,而不是系统范围内设置。

正如AlexP所说,PATH环境变量将具有最近分配的值。实际上,大多数情况下,当您设置PATH时,您会在新值中包含PATH的旧值,以便保留先前的条目。

因此,在实践中,当从多个文件设置PATH时,通常包含所有文件中给定的条目。但这仅发生在所有设置它的文件(除第一个文件外)通常引用PATH变量本身,从而导致其旧值被包含在新值中。

因此,您实际上正在请求各个文件中PATH设置产生效果的顺序。

通常,设置PATH的常见通用位置如下所示,按照用户登录时生效的顺序列出,而不是你通常应该考虑使用它们的顺序。下面列出的每个位置都是在某些情况下设置PATH的合理选择,但只有少数几个是大多数时间内的好选择。

在下面的列表中,你会看到一些目录名,比如~/.profile。如果你对波浪线扩展不熟悉,~/指的是当前用户的主目录。我主要使用这种语法是为了紧凑性。它在shell脚本中受支持,但在PAM配置文件中不受支持。

1. 对于所有用户: /etc/environment

PAM在Ubuntu上会导致环境变量被设置,如果存在/etc/environment文件,默认情况下是存在的。这就是所有用户的环境变量最常见的设置方式。

$ cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

如果你必须为所有用户帐户设置环境变量,而不仅仅是你的用户帐户,那么修改那个文件可能是最好的选择。我建议先备份它。备份此文件的一种方法是运行:
sudo cp /etc/environment /etc/environment.orig

不一定需要使用.orig扩展名 -- 你可以随意给备份文件起一个不会引起混淆或已被使用的名称(除了.orig.old.backup.bak是常见的)。

你可以像编辑其他文件一样以root用户身份编辑此文件(例如:sudoedit /etc/enviromnmentsudo nano -w /etc/environmentgksudo gedit /etc/environment等)。

/etc/environment不支持自动包含变量的旧值。但通常情况下这是不必要的,因为大多数时候你会通过编辑/etc/environment来为所有用户设置环境变量,而当用户登录时,你希望它保持初始值。然后用户可以根据需要进行更改。让用户能够这样做通常是很好的。

2. 对于所有用户: /etc/security/pam_env.conf

PAM从/etc/security/pam_env.conf文件中读取所有用户的环境变量,其语法与每个用户的~/.pam_environment文件相同(见下文)。

当相同的环境变量在/etc/environment/etc/security/pam_env.conf两个文件中都设置时,将使用pam_env.conf中的值,即使该值被指定为DEFAULT而不是OVERRIDE

然而,当您用pam_env.conf中的内容替换environment中的一行时,您可以包含被替换值的内容。有关详细信息,请参阅下面关于.pam_environment的部分(因为它使用相同的语法)。

通常情况下,不需要编辑pam_env.conf如果您这样做,务必非常小心,因为一个格式错误的行通常会导致所有正常用户账户无法登录!例如,默认的pam_env.conf包含以下行:

#PATH           DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11

这是几个例子之一。它示范了如何使用 \ 将一个赋值拆分成多行。假设您只取消注释了第一行,但忘记了取消注释第二行:

PATH           DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11

别这样做!

我不小心测试了一下,结果导致任何用户都无法成功登录。为了修复这个问题,我不得不进入恢复模式并将其改回来。(幸运的是,我在一个仅用于测试的虚拟机上进行了这个操作,所以没有给我带来任何麻烦。)

3. 对于单个用户:用户主目录中的.pam_environment

设置单个用户的环境变量的一种方法是让该用户编辑(或创建)位于其主目录中的.pam_environment文件。在这个文件中设置的值会覆盖全局的/etc/environment文件中设置的值。

.pam_environment 不是在创建用户帐户时复制到用户主文件夹骨架文件的一部分。但是,如果在您的主目录中创建该文件,则可以使用它来设置环境变量,例如 PATH。与 /etc/environment(但类似于/etc/security/pam_env.conf)不同,每个用户的 .pam_environment 文件支持将环境变量的旧值扩展为新值。但它们不是 shell 脚本,您必须使用特殊的语法来实现这一点,其与您在 .profile 等文件中使用的语法略有不同。

例如,如果您在主目录中有一个名为 bin2 的目录,您想将其添加到 PATH 的末尾,则可以通过将此行添加到 .pam_environment 中来实现:

PATH DEFAULT=${PATH}:/home/@{PAM_USER}/bin2

请参阅“~/.pam_environment”子节“EnvironmentVariables”(以上示例是基于此处适应的),以及“man pam_env”“man pam_env.conf”以获取更多详细信息。
尽管曾经被宣传为Ubuntu用户更改或添加环境变量的首选方式,并且仍然被认为是一个合理和可接受的选择,但在编辑.pam_environment文件时,你应该小心。与对系统范围的/etc/security/pam_env.conf文件的编辑一样(参见上文),用户的.pam_environment文件中存在格式错误的行将阻止登录成功。(这次我特意测试了一下。)有关建议如何演变的信息,请参阅Gunnar Hjalmarsson评论下方以及这个ubuntu-devel讨论
这样的错误通常比在pam_env.conf中出现的格式错误要轻微得多,因为它只影响一个用户。然而,在只有一个允许登录的桌面Ubuntu系统中,如果在编辑.pam_environment时犯了这样的错误,那么它将和编辑pam_env.conf时犯的错误一样糟糕--如果你还没有登录,你将无法修复它,除非进入恢复模式(或从活动的USB等启动)。
(如果你有其他用户账户,那么你可以作为另一个用户登录并解决问题。即使他们不是管理员,也不能使用sudo切换到root用户,但他们仍然可以运行su your-account,并被提示输入你的密码(而不是他们的密码)。然而,guest账户无法做到这一点,因为它被禁止使用su来扮演其他用户的身份。)
4. 对于所有用户:/etc/profile和/etc/profile.d/目录中的文件
Bourne兼容的shell(包括Ubuntu中默认的用户shell bash)在作为登录shell调用时会运行/etc/profile中的命令。
Ubuntu的/etc/profile以此结束:
if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

这会导致任何位于/etc/profile.d/目录中以.sh结尾的文件中的命令也会被执行。

大多数显示管理器也会对/etc/profile中的命令(以及/etc/profile.d/中的文件)在图形登录时进行运行。然而,并不是所有显示管理器都会如此,这正是使用PAM提供的功能的一个重要优势所在(参见上文)——除非该系统永远不会有任何图形登录,例如,如果它是一个没有安装GUI的服务器。

在传统上,我们会在/etc/profile中设置系统范围的环境变量,但这通常不再是最佳选择。如果您无法在/etc/environment中设置环境变量,并且您必须为所有用户设置它,那么创建一个新文件在/etc/profile.d/中可能比编辑/etc/profile本身更好。其中一个原因是,在升级Ubuntu时,可能会有一个新的默认/etc/profile文件。根据您执行升级的方式,要么保留旧文件(包括您的更改),放弃特定的更新配置文件,要么提示您处理该情况。

当相同的环境变量在/etc/profile/etc/profile.d中的一个或多个文件中设置时,哪个会生效?这取决于在/etc/profile中设置它们的命令出现在profile.d文件被加载之前还是之后(通过我上面引用的代码)。/etc/profile中的命令按照它们出现的顺序执行。

/etc/profile是一个shell脚本,其语法与上述PAM配置文件的语法不同。它的语法与用户个人的~/.profile文件相同(见下文)。

如果您需要编写代码来决定是否将特定目录添加到PATH中(并且对所有用户都有效),您将无法使用/etc/environment/etc/security/pam_env.conf来实现。这可能是更好地使用/etc/profile/etc/profile.d/的主要情况。

5. 对于一个用户:用户的家目录中的.bash_profile

如果用户有~/.bash_profile,bash将使用它而不是~/.profile~/.bash_login(见下文)。通常情况下,您不应该在您的家目录中有一个.bash_profile

如果您这样做,通常应该包含一个命令来源化~/.profile(例如,. "$HOME/.profile")。否则,每个用户的.profile文件的内容将不会运行。

6. 对于一个用户:用户主目录中的.bash_login

如果用户有~/.bash_login,bash将使用它而不是~/.profile(见下文),除非存在~/.bash_profile,在这种情况下,除非从`~/.bash_login源化,否则不会使用其他任何文件。

.bash_profile一样,您通常不应该在您的主目录中拥有.bash_login文件。

7. 对于一个用户:用户主目录中的.profile

当以Bourne风格的shell作为登录shell运行时,它会运行/etc/profile中的命令(通常包括导致在/etc/profile.d/文件中的命令被运行的命令--请参见上文)。之后,它会运行用户主目录下.profile中的命令。这个文件对每个用户都是独立的。(如果存在的话,Bash实际上会运行.bash_profile.bash_login--但是,在Ubuntu系统上,这些文件很少存在或者根本不存在。有关详细信息,请参见上文和6.2 Bash Startup Files in Bash手册。)
因此,~/.profile是用户在登录时放置命令的主要位置。这是您设置PATH的传统位置,但由于Ubuntu具有pam_env模块并支持~/.pam_environment,您应该考虑使用它。
与/etc/profile一样,不是所有的显示管理器都会在图形登录时运行此文件,尽管大多数会。这就是为什么更喜欢使用~/.pam_environment来设置环境变量的原因(就像有人更喜欢/etc/environment而不是/etc/profile一样)。
在.pam_environment中设置PATH时,可以展开环境变量,包括PATH本身(参见上文)。然而,如果您需要以更复杂的方式设置PATH,可能需要使用.profile文件。特别是,如果您想要每次用户登录时检查目录是否存在,并且只有在存在时将其添加到PATH中,那么您将无法使用.pam_environment文件将该目录添加到PATH中。
例如,在Ubuntu上,默认的每个用户.profile文件以前是以以下内容结尾的:
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

看一下 Gunnar HjalmarssonByte Commander's answer 上的 comment,详细了解一下。
这段代码检查你的主目录是否有一个名为 bin 的子目录。如果有,它会将该子目录添加到你的 PATH 变量的开头位置。 该列表并未包含所有可能性。 当用户登录时,环境变量的设置方式还与登录类型有关。例如,你可能会偶尔遇到仅用于图形界面登录或基于SSH的远程登录的环境变量。以上列表并不涵盖这些情况。
我忽略了一些文件,其中人们有时会定义环境变量,例如`~/.bashrc`和`/etc/bash.bashrc`,因为它们通常不被推荐用作设置`PATH`的位置,并且很少需要实际使用它们来做这个目的。如果你使用这些文件来添加目录到`PATH`,那么它们有时会被重复添加,当你检查`$PATH`时会非常混乱。(在极端情况下,这可能会减慢速度,但通常只是为了保持一切干净和可理解。)
由于`bash`是Ubuntu默认的用户登录Shell,而大多数用户使用它或其他兼容POSIX的Shell,所以我省略了关于如何在其他非Bourne风格的Shell(如`tcsh`)中设置环境变量的信息。

2[comment #1 of 2] 感谢您提供这么详细的描述!(我进行了一些小修改。)然而,对于推荐的方式,我还有一些疑问。几年前,EnvironmentVariables 中提到 /etc/environment/~/.pam_environment唯一推荐的文件。在与开发人员咨询过之后,我将其改为在 PAM 和 /etc/profile.d/*.sh/~/.profile 之间保持中立,并且我仍然倾向于这样看待它。 - Gunnar Hjalmarsson
2你提到了几个支持PAM的论点。支持/etc/profile.d/*.sh~/.profile的重要论点是语法更简单,并且lightdm/gdm在出现错误时也比较宽容(即使有语法错误,也不会阻止你登录,只会显示警告信息)。 - Gunnar Hjalmarsson
你说的 pam_env.so 是指 pam_env.conf 吗? - Johan Boulé
@JohanBoulé 是的,我确实是指 pam_env.conf。谢谢!我已经编辑好了。 - Eliah Kagan
在第四条中,"Ubuntu的/etc/profile.d结尾是否应该改为"Ubuntu的/etc/profile结尾?" - DK Bose
@DKBose 是的,绝对没错。谢谢!(已修正。) - Eliah Kagan

/etc/environment文件不是一个脚本文件,你不能在那里使用export命令,也不支持类似$HOME的变量扩展,只能使用简单的变量=值对。所以要使用该文件,你只需要将你的路径追加到现有定义中,它专门用于系统范围的环境变量设置,每行一个。具体来说,该文件存储了系统范围的区域设置和路径设置。

~/.profile - 每当执行bash shell时,都会执行此文件,通常推荐用于环境变量设置,但它的缺点是只有登录shell才会调用它,因此为了使其生效,你需要注销并重新登录,或者至少启动一个新的登录shell。


设置环境变量的首选位置取决于几个因素:
1. 您是否是唯一使用计算机的人:
- 在这种情况下,最好的设置位置将是`/etc/environment`,因为没有未经授权的访问风险。
2. 如果系统被多个用户使用:
- 如果所有用户都应该访问这些变量,则位置应为`/etc/environment`; - 如果各个用户应该有选择性地访问它们,则每个用户都应在其各自的主目录中的`~/.profile`中设置自己的变量。
系统会在读取`~/.profile`之前先读取`/etc/environment`。不会发生连接操作,就像Alex P所说,路径的最后一个赋值起作用。
要更详细地了解决定~/.profile/etc/environment与其他位置的关系的因素,请点击这里这里。这些因素将影响您如何使用这些位置。


检查你的/etc/environment文件。它应该只包含字面路径,不应包含类似于"$PATH=$PATH:<任意要添加的路径>"的内容。
这样会导致系统出错,并使你陷入登录循环中。