如何正确添加路径到PATH?


921

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

这条路:

export PATH=~/opt/bin:$PATH

或这个?

export PATH=$PATH:~/opt/bin

printf'\ nPATH = $ PATH:“添加路径” \ nexport PATH \ n'>>〜/ .bashrc
Sudoer 2014年


如果已经添加了一些路径,例如PATH=$PATH:$HOME/.local/bin:$HOME/bin,可以通过用:分隔添加其他路径PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin
Sandeepan Nath

2
这些答案适用于所有Linux版本吗?
Ungeheuer

Answers:


1032

简单的东西

PATH=$PATH:~/opt/bin

要么

PATH=~/opt/bin:$PATH

取决于您是要添加~/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。定义环境变量的正确位置PATH~/.profile(或(~/.bash_profile如果您不关心bash以外的其他外壳的话))。请参阅它们之间有什么区别,我应该使用哪一个?

不要将其放在/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

关于除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",或者PATH=~/opt/bin:$PATH; export PATH(或者PATH=$HOME/opt/bin:$PATH; export PATH为了移植到不接受export var=value也没有进行波浪号扩展的Bourne shell )。

¹ 在Bourne外壳中并非如此(就像在实际的Bourne外壳中一样,而不是现代POSIX风格的外壳中),但是如今您不太可能遇到这样的旧外壳。


仍然无法理解导出的复杂性。您能简化一下吗?
priojeet priyom

@priojeetpriyom简单说明:不需要export
吉尔斯

谢谢您的回答,非常详细。您说“ 您不应该在〜/ .bashrc中定义环境变量 ”,但是很不幸,我在系统上安装的修改路径的程序(FZF和Rust's Cargo)中有100%修改了.bashrc。我认为因为FZF也是用Rust编写的,所以它也遵循Rust的模式。
icc97

83

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

特别地,从安全的角度来看,将路径添加到前端是危险的,因为如果某人可以获得对您的的写访问权~/opt/bin,他们可以在其中放置其他内容ls,而您可能会改用其他内容。的/bin/ls没有注意到。现在想象一下,对于ssh您的浏览器还是选择相同的东西(将。放在您的路径中同样如此)。


6
但是,如果您想拥有自己的定制版本ls,则需要将其放在目录之前/bin
Barmar

16
或别名ls = myls
waltinator

36

我对问题2感到困惑(由于与问题无关,将其从问题中删除):

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

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

但这不是因为第二个分配不仅附加了 ~/opt/node/bin,还PATH分配了先前分配的全部。

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

export PATH=$PATH:~/opt/bin:~/opt/node/bin

但出于可读性考虑,我宁愿为一条路径分配一份。

如果你说

PATH=~/opt/bin

这就是您路径中的全部内容。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

2
您对问题2的示例是正确的,它可以工作。我系统上另一个与PATH相关的问题使我感到困惑。抱歉
Paolo

26

追加/追加的防弹方式

选择追加还是前置有很多考虑因素。其他答案涵盖了其中许多内容,因此在此不再赘述。

重要的一点是,即使系统脚本不使用此代码(我想知道为什么)* 1$HOME/bin向路径环境变量添加路径(例如)的防弹方式也是:

PATH="${PATH:+${PATH}:}$HOME/bin"

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

PATH="$HOME/bin${PATH:+:${PATH}}"

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

这样可以避免在$PATH最初为空时产生虚假的前导/尾随冒号,冒号可能会产生不良后果,并且可能会带来噩梦,难以捉摸(此答案简要介绍了awk-way 的情况)。

说明(来自Shell参数扩展):

${parameter:+word}

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

因此,${PATH:+${PATH}:}将其扩展为:1)如果PATH为null或未设置,则为空; 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}}
...

24

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

PATH=/data/myscripts:$PATH

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

PATH=$PATH:/data/myscripts

但是上述操作还不够,因为在脚本中设置环境变量时,该更改仅在脚本中有效。解决此限制的方法只有两种:

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

例子:

$HOME/myscript.sh
source $HOME/myscript.sh

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

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

PATH=$PATH:/data/myscripts
export PATH

有效地将这两行代码放入bash程序中。因此在bash中,$ PATH变量包含$HOME/myscript.sh,并且由于export语句的原因,bash调用的任何程序都具有更改后的$PATH变量。而且,由于从bash提示符运行的任何程序都被bash调用,因此对于从bash提示符运行的任何内容,新路径均有效。

最重要的是,要将新目录添加到路径,必须在外壳程序所包含的脚本内将目录追加或添加到$ PATH环境变量中,并且必须导出$PATH环境变量。

更多信息在这里


19

一段时间以来,我一直使用两个函数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')"
}

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

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

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

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

现在,如果路径已经存在而没有加倍,则可以将其移到最前面。


相关且更
通配符

9

我不能说其他版本,但是Ubuntu有一个文件/ etc / environment,这是所有用户的默认搜索路径。由于我的计算机仅由我使用,因此除非在脚本中添加了临时添加内容,否则我会将所需的所有目录放在该目录中。


6

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

  1. 添加实际上不是目录的路径。
  2. 添加已PATH采用相同形式的路径。
  3. 添加相对路径(因为搜索的实际目录会随着您更改当前工作目录而更改)。
  4. 添加已经PATH采用其他形式的路径(即,由于使用符号链接或而引起的别名..)。
  5. 如果您避免执行4,PATH则在打算覆盖中的其他条目时,请勿将路径移到其前面PATH

在上述情况下,此(仅限Bash)功能会做“正确的事”(例外,请参阅下文),返回错误代码,并为人类打印好消息。不需要时可以禁用错误代码和消息。

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"
}

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


关于相对路径:使用“ -r”开关怎么样?它将在不首先将其设置为绝对路径的情况下添加路径,并且还会在添加路径之前将其视为绝对路径?如果这是脚本,则可以在其他shell中使用它。将其作为功能有什么好处?漂亮的代码!
houiui

1
@hoijui它必须是一个函数,因为它正在修改当前环境。如果是脚本,它将修改运行该脚本的子进程的环境,并且当脚本退出时,您将拥有与$PATH以前相同的环境。至于-r,不,我认为其中的相对路径$PATH太不可靠,很怪异(您的路径每次更改都会改变cd!)以至于无法在通用工具中支持类似的功能。
Curt J. Sampson

5

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

编辑之前,echo $PATH返回:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

编辑/etc/paths并重新启动外壳程序后,$ PATH变量将附加/pathname。确实,echo $PATH返回:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname

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


3
将文件添加到/etc/paths.d目录比编辑/ etc / paths文件本身更好。
rbrewer

4

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

export PATH=$PATH:/new-path/

为了将此更改应用于您打开的每个外壳,请将其添加到调用该外壳时的文件中。在不同的外壳中可以是:

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

例如

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

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


4

这是我的解决方案:

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

一个不错的简单班轮,不会拖尾 :


1
-bash:awk:没有这样的文件或目录-bash:sed:没有这样的文件或目录
davidcondrey

1
@davidcondrey-awk和sed是非常常见的外部命令。此答案提供了一种纯方法来实现此目的,因此即使在不存在awk和/或sed(或它们各自的目录不在路径中的情况下)也可以使用
sancho.s
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.