如何从 $PATH 中删除重复的目录?

如何从 $PATH 中删除重复的目录?

在我的某些终端窗口中,PATH变量中有重复的条目;如下所示:

PATH=/a/b:/c/d:/a/b:/c/d:/e/f:/a/b

我猜罪魁祸首是我的一些脚本中的如下几行:

PATH=/a/b:$PATH

找到这个、那个之后,这个又PATH变得很长。这是问题:

是否有bash命令来清除PATH和类似的环境变量?它应该是一个bash脚本,因为不能执行实用程序并期望它更改调用 shell 的环境。

在上面的例子中,清理后PATH看起来应该是这样的:

PATH=/a/b:/c/d:/e/f

答案1

最好不要创建重复项,而不是事后尝试删除它们。使用我在.bashrc添加私人bin/目录时使用的技术可以轻松避免这种情况:

[ "${PATH#*$HOME/bin:}" == "$PATH" ] && export PATH="$HOME/bin:$PATH"

我在进行更新时执行了此操作.bashrc,并且想在不重新启动 shell 的情况下重新运行它。

如果要在末尾添加目录,$PATH则需要使用前导冒号:

[ "${PATH#*:$HOME/bin}" == "$PATH" ] && export PATH="$PATH:$HOME/bin"

您可以使用参数扩展来逐步PATH删除重复项,但这有点复杂,而且您需要决定应该保留哪个位置。大致如下:-

OLDPATH="$PATH"; NEWPATH=""; colon=""
while [ "${OLDPATH#*:}" != "$OLDPATH" ]
do  entry="${OLDPATH%%:*}"; search=":${OLDPATH#*:}:"
    [ "${search#*:$entry:}" == "$search" ] && NEWPATH="$NEWPATH$colon$entry" && colon=:
    OLDPATH="${OLDPATH#*:}"
done
NEWPATH="$NEWPATH:$OLDPATH"
export PATH="$NEWPATH"

在匆忙写下这篇文章并测试它之后,我应该已经消除了大部分错误,它应该是一个足够的指南,指导你需要做什么。它留下了最后的任何重复的发生,如果您首先使用我的脚本来避免重复,它们就会出现在这里。在脚本中,当然需要使用./source命令来调用它。

答案2

我编写了这个简单的 Python 3 脚本:

import os
    
# grab $PATH
path = os.environ['PATH'].split(':')

# normalize all paths
path = map(os.path.normpath, path)

# remove duplicates via a dictionary
clean = dict.fromkeys(path)

# combine back into one path
clean_path = ':'.join(clean.keys())

# dump to stdout
print(f"PATH={clean_path}")

我将脚本放在中$HOME/scripts,然后将此行添加到我的末尾.bashrc

eval $(python3 $HOME/scripts/clean-path.py)

从 Python 3.7 开始,字典保证保留顺序,因此clean_path目录的顺序与原始目录的顺序相同PATH

答案3

以下是 bash 示例。

#!/bin/bash
if [ -n "$PATH" ]; then
  old_PATH=$PATH:; PATH=
  while [ -n "$old_PATH" ]; do
    x=${old_PATH%%:*}       # the first remaining entry
    case $PATH: in
      *:"$x":*) ;;          # already there
      *) PATH=$PATH:$x;;    # not there yet
    esac
    old_PATH=${old_PATH#*:}
  done
  PATH=${PATH#:}
  unset old_PATH x
fi
echo ${PATH}

答案4

这是一个漂亮的印刷版本

if [[ -x /usr/bin/awk ]]; then
  export PATH="$(echo "$PATH" | /usr/bin/awk 'BEGIN { RS=":"; } { sub(sprintf("%c$", 10), ""); if (A[$0]) {} else { A[$0]=1; printf(((NR==1) ?"" : ":") $0) }}')"
  echo $PATH
else
  echo "AWK is not located at /usr/bin/awk" # for the truly paranoid
fi

下面是单行版本

if [[ -x /usr/bin/awk ]]; then export PATH="$(echo "$PATH" | /usr/bin/awk 'BEGIN { RS=":"; } { sub(sprintf("%c$", 10), ""); if (A[$0]) {} else { A[$0]=1; printf(((NR==1) ?"" : ":") $0) }}')" ; fi

相关内容