如何正确添加路径到PATH?

Pao*_*olo 1174 bash path environment-variables bashrc

我想知道必须向PATH环境变量添加新路径的位置。我知道这可以通过编辑来完成.bashrc(例如),但不清楚如何做到这一点。

这边走:

export PATH=~/opt/bin:$PATH
Run Code Online (Sandbox Code Playgroud)

或这个?

export PATH=$PATH:~/opt/bin
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 1316

简单的东西

PATH=$PATH:~/opt/bin
Run Code Online (Sandbox Code Playgroud)

或者

PATH=~/opt/bin:$PATH
Run Code Online (Sandbox Code Playgroud)

取决于您是想~/opt/bin在末尾添加(在所有其他目录之后搜索,以防在多个目录中存在同名程序)还是在开头添加(在所有其他目录之前搜索)。

您可以同时添加多个条目。PATH=$PATH:~/opt/bin:~/opt/node/bin或订购工作的变化就好了。不要放在export行首,因为它有额外的复杂性(参见下面的“关于除 bash 之外的 shell 的注意事项”)。

如果您PATH由许多不同的组件构建,则最终可能会出现重复的条目。请参阅如何添加由 Unix 哪个命令发现的主目录路径?使用 awk 命令删除重复的 $PATH 条目以避免添加重复项或删除它们。

~/bin顺便说一下,有些发行版会自动放入您的 PATH(如果存在)。

把它放在哪里

放线修改PATH~/.profile,或者~/.bash_profile如果这就是你所拥有的。

注意,~/.bash_rc不是任何程序读取的,~/.bashrc是bash交互实例的配置文件。您不应在~/.bashrc. 定义环境变量的正确位置,例如PATHis ~/.profile(或者~/.bash_profile如果您不关心 bash 以外的 shell)。请参阅它们之间有什么区别,我应该使用哪一种?

不要把它放进去/etc/environment~/.pam_environment:这些不是 shell 文件,你不能像$PATH那里那样使用替换。在这些文件中,您只能覆盖一个变量,而不能添加到它。

某些系统脚本中的潜在并发症

export如果变量已经在环境中,则不需要:变量值的任何变化都会反映在环境PATH中。¹ 几乎总是在环境中;所有的 Unix 系统很早就设置了它(实际上通常在第一个进程中)。

在登录时,您可以依赖PATH已经在环境中,并且已经包含一些系统目录。如果您正在编写可能在设置某种虚拟环境时提前执行的脚本,您可能需要确保它PATH是非空的并已导出:如果PATH仍未设置,则类似PATH=$PATH:/some/directory将设置PATH:/some/directory,以及空组件开头表示当前目录(如.:/some/directory)。

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi
Run Code Online (Sandbox Code Playgroud)

bash 以外的 shell 的注意事项

在bash和ksh和zsh的,export是特殊的语法,都PATH=~/opt/bin:$PATHexport PATH=~/opt/bin:$PATH连做正确的事。在其他 Bourne/POSIX 样式的 shell 中,例如 dash(/bin/sh在许多系统上),export被解析为普通命令,这意味着两个不同之处:

所以在像破折号这样的 shell 中,export PATH=~/opt/bin:$PATH设置PATH为文字字符串,~/opt/bin/:后跟PATH第一个空格的值。 PATH=~/opt/bin:$PATH(一个简单的任务)不需要引号并且做正确的事情。如果要export在可移植脚本中使用,则需要编写export PATH="$HOME/opt/bin:$PATH", or PATH=~/opt/bin:$PATH; export PATH(或PATH=$HOME/opt/bin:$PATH; export PATH为了可移植到甚至不接受export var=value也不进行波浪号扩展的 Bourne shell )。

¹这在 Bourne shell 中并非如此(如在实际的 Bourne shell 中,而不是现代 POSIX 样式的 shell),但是现在您极不可能遇到这样的旧 shell。

  • @priojeetpriyom 简单的解释:你不需要`export`。 (7认同)
  • 谢谢你的回答,非常详细。你说“*你不应该在 ~/.bashrc* 中定义环境变量”,但不幸的是,我在我的系统上安装的修改路径的程序(FZF 和 Rust 的 Cargo)100% 修改了`.bashrc` 中的路径. 我假设因为 FZF 也是用 Rust 编写的,所以它遵循 Rust 的模式。 (2认同)

Ulr*_*arz 94

无论哪种方式都有效,但它们不做同样的事情:PATH从左到右检查的元素。在您的第一个示例中,可执行文件 in~/opt/bin将优先于已安装的可执行文件,例如 in /usr/bin,这可能是您想要的,也可能不是。

特别是,从安全的观点来看,这是很危险的路径添加到前面,因为如果有人能得到您的写入权限~/opt/bin,他们可以把,例如,不同ls在那里,你会那么很可能改用的/bin/ls没有注意到。现在想象相同的ssh或您的浏览器或选择......(将 . 放在您的路径中也是如此。)

  • 或别名 ls=myls (20认同)
  • 但是如果你想拥有自己的、定制版本的 `ls`,你需要把它放在 `/bin` 之前的目录中。 (8认同)

san*_*lio 60

Appending/Prepending 的防弹方式

尝试不使用

PATH=$PATH:~/opt/bin
Run Code Online (Sandbox Code Playgroud)

或者

PATH=~/opt/bin:$PATH
Run Code Online (Sandbox Code Playgroud)

为什么? 选择附加还是前置需要考虑很多因素。其中许多在其他答案中都有涉及,因此我不会在此重复。

重要的一点是,即使系统脚本不使用这个(我不知道为什么)*1~/opt/bin向 PATH 环境变量添加路径(例如,)的防弹方法是

PATH="${PATH:+${PATH}:}~/opt/bin"
Run Code Online (Sandbox Code Playgroud)

用于附加(而不是PATH="$PATH:~/opt/bin")和

PATH="~/opt/bin${PATH:+:${PATH}}"
Run Code Online (Sandbox Code Playgroud)

用于前置(而不是PATH="~/opt/bin:$PATH"

这避免了$PATH最初为空时的虚假前导/尾随冒号,这可能会产生不良副作用,并可能成为噩梦,难以找到(此答案简要介绍了这种情况awk)。

说明(来自Shell Parameter Expansion):

${parameter:+word}
Run Code Online (Sandbox Code Playgroud)

如果parameter为 null 或未设置,则不替换任何内容,否则替换 的扩展word

因此,${PATH:+${PATH}:}扩展为:

  1. 什么都没有,如果PATH为空或未设置,
  2. ${PATH}:,如果PATH设置。

注意:这是针对 bash 的。


*1我刚刚发现像 `devtoolset-6/enable` 这样的脚本实际上使用了这个,
$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...
Run Code Online (Sandbox Code Playgroud)

  • `${PATH:+:${PATH}}` 很令人困惑,因为第一个 `:` 是语法的一部分,第二个 `:` 是列表分隔符。 (3认同)
  • 好吧,我想你必须习惯它。 (3认同)
  • `:` 是上下文相关的。这是人工智能的一种基本形式。:-) (3认同)

小智 40

我对问题 2 感到困惑(因为它是由于一个不相关的问题而从问题中删除的):

在不同行上附加更多路径的可行方法是什么?最初我认为这可以解决问题:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin
Run Code Online (Sandbox Code Playgroud)

但这不是因为第二个分配不仅 append ~/opt/node/bin,而且还整个PATH先前分配。

这是一个可能的解决方法:

export PATH=$PATH:~/opt/bin:~/opt/node/bin
Run Code Online (Sandbox Code Playgroud)

但为了可读性,我更愿意为一条路径分配一项任务。

如果你说

PATH=~/opt/bin
Run Code Online (Sandbox Code Playgroud)

这就是您的 PATH中的全部内容。PATH 只是一个环境变量,如果你想添加到 PATH,你必须用你想要的内容重建变量。也就是说,您对问题 2 给出的示例正是您想要做的,除非我完全没有抓住问题的要点。

我在我的代码中使用这两种形式。我有一个通用配置文件,我安装在我工作的每台机器上,看起来像这样,以适应可能丢失的目录:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done
Run Code Online (Sandbox Code Playgroud)

  • 您对问题 2 的示例是正确的,它有效。我系统上的另一个 PATH 相关问题让我感到困惑。对不起。 (2认同)

Ste*_*own 25

Linux 使用$PATH环境变量确定可执行搜索路径。要将目录 /data/myscripts 添加到$PATH环境变量的开头,请使用以下命令:

PATH=/data/myscripts:$PATH
Run Code Online (Sandbox Code Playgroud)

要将该目录添加到路径的末尾,请使用以下命令:

PATH=$PATH:/data/myscripts
Run Code Online (Sandbox Code Playgroud)

但是前面的方法还不够,因为当您在脚本中设置环境变量时,该更改仅在脚本内有效。只有两种方法可以解决此限制:

  • 如果在脚本中导出环境变量,则它在脚本调用的任何程序中都有效。请注意,它在调用脚本的程序中无效。
  • 如果调用脚本的程序通过包含而不是调用来执行此操作,则脚本中的任何环境更改在调用程序中都是有效的。这种包含可以通过 dot 命令或 source 命令来完成。

例子:

$HOME/myscript.sh
source $HOME/myscript.sh
Run Code Online (Sandbox Code Playgroud)

包含基本上将“被调用”脚本合并到“调用”脚本中。它就像 C 中的 #include。所以它在“调用”脚本或程序中是有效的。但是当然,它在调用程序调用的任何程序或脚本中都无效。为了使其在调用链中一直有效,您必须使用导出命令来遵循环境变量的设置。

例如,bash shell 程序通过包含来合并文件 .bash_profile 的内容。将以下 2 行放在 .bash_profile 中:

PATH=$PATH:/data/myscripts
export PATH
Run Code Online (Sandbox Code Playgroud)

有效地将这两行代码放在 bash 程序中。因此,在 bash 中, $PATH 变量包含$HOME/myscript.sh,并且由于导出语句,bash 调用的任何程序都具有更改的$PATH变量。并且因为您从 bash 提示符运行的任何程序都由 bash 调用,所以新路径对您从 bash 提示符运行的任何程序都有效。

最重要的是,要将新目录添加到路径中,您必须将目录附加到或预先添加到 shell 中包含的脚本中的 $PATH 环境变量,并且必须导出$PATH环境变量。

更多信息在这里


小智 22

一段时间以来,我一直使用两个函数pathaddpathrm它们有助于将元素添加到路径中,而无需担心重复。

pathadd接受一个路径参数和一个可选after参数,如果提供该参数将附加到PATH否则它在它前面。

在几乎所有情况下,如果您要添加到路径中,那么您可能希望覆盖路径中已有的任何内容,这就是我选择默认添加的原因。

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}
Run Code Online (Sandbox Code Playgroud)

将这些放在您希望更改 PATH 环境的任何脚本中,您现在可以这样做了。

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH
Run Code Online (Sandbox Code Playgroud)

如果路径已经存在,您可以保证不会添加到路径中。如果您现在要确保/baz/bat是在开始。

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH
Run Code Online (Sandbox Code Playgroud)

现在任何路径都可以移动到前面,如果它已经在路径中而不会加倍。


小智 12

我不能说其他发行版,但 Ubuntu 有一个文件 /etc/environment,这是所有用户的默认搜索路径。由于我的计算机仅供我使用,因此我将我想要的任何目录放在我的路径中,除非它是我放在脚本中的临时添加。


Ami*_*4x7 10

要向PATH环境变量添加新路径:

export PATH=$PATH:/new-path/
Run Code Online (Sandbox Code Playgroud)

要将此更改应用于您打开的每个 shell,请将其添加到 shell在调用时将作为来源的文件。在不同的 shell 中,这可以是:

  • Bash Shell:~/.bash_profile、~/.bashrc 或配置文件
  • Korn Shell:~/.kshrc 或 .profile
  • Z Shell:~/.zshrc 或 .zprofile

例如

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH
Run Code Online (Sandbox Code Playgroud)

您可以在上面的输出中看到提供的路径。


cjs*_*cjs 8

在某些情况下,它使用PATH=/a/b:$PATH可能被认为是添加路径的“不正确”方式PATH

  1. 添加一个实际上不是目录的路径。
  2. 添加一个已经以PATH相同形式存在的路径。
  3. 添加相对路径(因为搜索的实际目录会随着您更改当前工作目录而更改)。
  4. 添加已PATH采用不同形式的路径(即,由于使用符号链接或 导致的别名..)。
  5. 如果你避免做 4,PATH当它打算覆盖PATH.

这个(Bash-only)函数在上述情况下做“正确的事情”(有一个例外,见下文),返回错误代码,并为人类打印好的消息。不需要时可以禁用错误代码和消息。

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}
Run Code Online (Sandbox Code Playgroud)

例外是此函数不会规范化PATH通过其他方式添加到的路径,因此如果路径的非规范别名在 中PATH,这将添加重复项。尝试规范化已经存在的路径PATH是一个冒险的命题,因为相对路径在传递给prepath时具有明显的含义,但是当已经在路径中时,您不知道添加时当前工作目录是什么。


小智 6

对我来说(在 Mac OS X 10.9.5 上),将路径名(例如/mypathname)添加到文件中/etc/paths效果很好。

编辑前,echo $PATH返回:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
Run Code Online (Sandbox Code Playgroud)

编辑/etc/paths并重新启动 shell 后,$PATH 变量将附加/pathname. 确实,echo $PATH返回:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname
Run Code Online (Sandbox Code Playgroud)

发生的事情是/mypathname已附加到$PATH变量。

  • 将文件添加到 /etc/paths.d 目录比编辑 /etc/paths 文件本身更好。 (3认同)

AJ.*_*AJ. 5

这是我的解决方案:

PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")
Run Code Online (Sandbox Code Playgroud)

一个不错的简单单衬,不会留下拖尾 :

  • -bash: awk: 没有这样的文件或目录 -bash: sed: 没有这样的文件或目录 (2认同)

归档时间:

查看次数:

2783588 次

最近记录:

4 年,7 月 前