如何干净地添加到 $PATH?

gol*_*cks 35 shell path

我想要一种向 $PATH、系统范围内或单个用户添加内容的方法,而无需多次添加相同的路径。

想要这样做的一个原因是,可以在 中进行添加.bashrc,这不需要登录,并且在使用(例如)lightdm从不调用 的系统上也更有用.profile

我知道有关如何从 $PATH清除重复项的问题,但我不想删除重复项。我想要一种仅在路径尚不存在时添加路径的方法

Joh*_*024 38

假设我们要添加的新路径是:

new=/opt/bin
Run Code Online (Sandbox Code Playgroud)

然后,使用任何 POSIX shell,我们可以测试是否new已经在路径中,如果不在,则添加它:

case ":${PATH:=$new}:" in
    *:"$new":*)  ;;
    *) PATH="$new:$PATH"  ;;
esac
Run Code Online (Sandbox Code Playgroud)

注意冒号的使用。如果没有冒号,我们可能会认为,比如说,new=/bin已经在路径中,因为它的模式匹配于/usr/bin。虽然 PATH 通常有很多元素,但也会处理 PATH 中元素为零和一的特殊情况。PATH 最初没有元素(为空)的情况由使用${PATH:=$new}which 分配PATH给($new如果它为空)来处理。以这种方式设置参数的默认值是所有 POSIX shell 的一个特性:请参阅POSIX 文档的第 2.6.2 节。)

一个可调用的函数

为方便起见,可以将上面的代码放到一个函数中。这个函数可以在命令行中定义,或者为了让它永久可用,将它放入你的 shell 的初始化脚本中(对于 bash 用户,这将是~/.bashrc):

pupdate() { case ":${PATH:=$1}:" in *:"$1":*) ;; *) PATH="$1:$PATH" ;; esac; }
Run Code Online (Sandbox Code Playgroud)

要使用此路径更新功能将目录添加到当前 PATH:

pupdate /new/path
Run Code Online (Sandbox Code Playgroud)

  • 如果`PATH` 为空,这将向`PATH` 添加一个空条目(即当前目录)。我想你需要另一个案例。 (3认同)
  • @CharlesBailey 不是另一个`case`。只需执行`case "${PATH:=$new}"`。有关类似的回退,请参阅我自己的答案。 (2认同)

gol*_*cks 10

/etc/profile.d调用中创建一个文件,例如mypath.sh(或任何你想要的)。如果您使用的是 lightdm,请确保它是可行的,否则使用/etc/bashrc或来自相同的文件。添加以下功能:

checkPath () {
        case ":$PATH:" in
                *":$1:"*) return 1
                        ;;
        esac
        return 0;
}

# Prepend to $PATH
prependToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$a:$PATH
                fi
        done
        export PATH
}

# Append to $PATH
appendToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$PATH:$a
                fi
        done
        export PATH
}
Run Code Online (Sandbox Code Playgroud)

$PATH 开头(前置)的内容优先于后面的内容,相反,结尾(附加)的内容将被前面的内容取代。这意味着如果您的 $PATH 是/usr/local/bin:/usr/bin并且gotcha在两个目录中都有一个可执行文件,则/usr/local/bin默认情况下将使用其中一个。

您现在可以 - 在同一个文件中,在另一个 shell 配置文件中,或从命令行 - 使用:

appendToPath /some/path /another/path
prependToPath /some/path /yet/another/path
Run Code Online (Sandbox Code Playgroud)

如果这是在 a 中.bashrc,它将防止该值在您启动新 shell 时出现多次。有一个限制,如果你想附加一些预先准备好的东西(即在 $PATH 中移动路径),反之亦然,你必须自己做。


cou*_*ode 5

你可以这样做:

echo $PATH | grep /my/bin >/dev/null || PATH=$PATH:/my/bin
Run Code Online (Sandbox Code Playgroud)

注意:如果您从其他变量构建 PATH,请检查它们是否为空,因为许多 shell 将 "" 解释为 "."。.


l0b*_*0b0 5

代码的重要部分是检查是否PATH包含特定路径:

printf '%s' ":${PATH}:" | grep -Fq ":${my_path}:"
Run Code Online (Sandbox Code Playgroud)

也就是说,保证在每个路径PATH上分隔由双方PATH分隔符(:),然后检查-q)是否为文字字符串(-F)组成的的PATH分离,你的路径,另一个PATH分离器中存在。如果没有,您可以安全地添加路径:

if ! printf '%s' ":${PATH-}:" | grep -Fq ":${my_path-}:"
then
    PATH="${PATH-}:${my_path-}"
fi
Run Code Online (Sandbox Code Playgroud)

这应该是POSIX 兼容的,并且应该适用于任何不包含换行符的路径。如果您希望它在与 POSIX 兼容的同时使用包含换行符的路径,则它会更复杂,但是如果您有一个grep支持-z,则可以使用它。


ter*_*don 5

多年来,我一直在各种~/.profile文件中随身携带这个小功能。它包含在/etc/profileRed Hat Linux 和衍生产品(CentOS、Fedora)中

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}
Run Code Online (Sandbox Code Playgroud)

因此,要在以下内容的开头添加一个新目录PATH

pathmunge /new/path
Run Code Online (Sandbox Code Playgroud)

最后:

pathmunge /new/path after
Run Code Online (Sandbox Code Playgroud)