从PATH变量中删除重复的条目


9

我经常修改.bashrc,然后将其来源。但是,当export PATH="~/bin:~/perl5/bin:$PATH"我的文件中有类似内容 时,PATH每次我获取文件时,环境变量都会增加。

例如,第一次获取.bashrc时,PATH变量由组成~/bin:~/perl5/bin:/usr/bin:/bin

第二次包含~/bin:~/perl5/bin:~/bin:~/perl5/bin:/usr/bin:/bin

第三次包含~/bin:~/perl5/bin:~/bin:~/perl5/bin:~/bin:~/perl5/bin:/usr/bin:/bin

有没有一种简单的方法可以使其仅添加PATH中尚未添加的任何内容?

Answers:


12

使用大多数发行版中可用的pathmunge()函数/etc/profile

pathmunge () {
if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
   if [ "$2" = "after" ] ; then
      PATH=$PATH:$1
   else
      PATH=$1:$PATH
   fi
fi
}

编辑:对于zsh用户,typeset -U <variable_name>将删除重复的路径条目。


谢谢!它不在/etc/profileDebian Lenny上,因此我将其包含在.bashrc
Christopher Bottoms 2010年

用法:pathmunge /some/path将放置/some/path在开始$PATHpathmunge /some/path after将放置/some/path在年底$PATH
克里斯托弗下装

看到做检查的清洁方式,如果在当前路径存在HEW目录,在现代的bash壳:if ! [[ $PATH =~ (^|:)$1($|:) ]] ; then
Christopher Cashell

我不会用这个。如果我的幼稚版本说PATH = / foo:$ PATH,则意味着我希望/ foo获胜。 pathmunge /foo before不能做到这一点。更好的方法是在开头添加/ foo,然后再删除重复项。
唐·哈奇

3

我遇到了这个问题,因此我使用了StackOverflow问题上列出的多种技术。以下是我用来对已经设置的实际PATH变量进行重复数据删除的内容,因为我不想修改基本脚本。

    tmppath=(${PATH// /@})
    array=(${tmppath//:/ })
    for i in "${array[@]//@/ }"
    do
        if ! [[ $PATH_NEW =~ "$i" ]]; then
            PATH_NEW="${PATH_NEW}$i:";
        fi
    done;
    PATH="${PATH_NEW%:}"
    export PATH
    unset PATH_NEW

您总是可以进一步优化它,但是我的原始代码中有额外的代码来显示正在发生的事情,以确保它正确设置了变量。要注意的另一件事是我执行以下操作

  1. 用@字符替换任何空格字符
  2. 分割数组
  3. 遍历数组
  4. 用空格替换元素字符串中的任何@字符

这是为了确保我可以处理带有空格的目录(具有Active Directory用户名的Samba主目录可以带有空格!)


警告:此实现存在一个重大错误!/bin如果还有其他条目,例如/usr/bin因为正则表达式匹配,即使两个条目不相同,也会删除它!
Sukima

这是修复该错误的替代实现:github.com/sukima/dotfiles/blob/…–
Sukima

1

明确设置路径。


谢谢。我尝试显式设置路径,但是我有一个在多个环境中使用的.bashrc文件,因此确切的默认PATH值并不总是相同。
Christopher Bottoms

1

仅一个字符串:

for i in $(echo $PATH|tr ":" "\n"|sort|uniq);do PATH_NEW="${PATH_NEW}$i:";done;PATH="${PATH_NEW%:}"

谢谢。这将使我感到困难的一个原因是,它按字母顺序(或ASCII字母顺序)对的内容重新排序$PATH。我喜欢将特定目录放在$PATH(如/home/username)的开头,以便运行我的可执行文件的个人副本,而不是内置的默认值。
Christopher Bottoms 2010年

1

我可以想到两种解决此问题的方法。第一个是用明确设置基础PATH的行开始.bashrc,这样,每次您获取它时,都会在添加其他目录之前将其重置为基础。

例如,添加:

# Reset the PATH to prevent duplication and to make sure that we include
# everything we want.
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

或者,您可以在将项目添加到路径之前检查它。为此,您可以使用以下方法:

if ! [[ $PATH =~ '~/perl5/bin' ]]
then
    PATH="~/perl5/bin:$PATH"
fi

但是,如果要添加很多条目,则后者趋于重复一些,因此,我倾向于坚持使用前者。如果您想使用此功能并计划添加许多条目,那么编写一个bash函数来处理它是明智的。

注意:第二个选项可能仅按现代版本bash的方式工作。正则表达式支持不是Bourne Shell(/ bin / sh)功能,在其他Shell中可能不存在。另外,可能不需要使用引号,甚至可能导致某些最新版本的bash出现问题。


谢谢。我尝试显式设置路径,但是我有一个在多个环境中使用的.bashrc文件,因此确切的默认PATH值并不总是相同。
Christopher Bottoms 2010年

您仍然可以通过签入脚本以查看本地主机名,然后为该服务器设置适当的绝对路径来处理该问题。
Christopher Cashell

只是一个错字:!在中丢失if。另外,(对我来说)很容易将其制成一个循环使用空格分隔的参数的函数,因此您可以这样说:add_to_PATH ~/perl5/bin ~/.bin unix.stackexchange.com/a/4973/28760(我想case那里使用的语句更便于移植) ,但您if对我更清楚了)。这个问题也加了perl5的EDIT奇怪的巧合!
13ren

@ 13ren:感谢您的来信。我还意识到我在PATH设置行中使用了单引号,而不是我应该使用的双引号。如所写,它将用变量名替换您现有的路径。糟糕!显然,这对我来说是错别字的输入;两者都已修复。
Christopher Cashell 2012年

0

这是我的解决方案: PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

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

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.