使用 awk 命令删除重复的 $PATH 条目

使用 awk 命令删除重复的 $PATH 条目

我正在尝试编写一个 bash shell 函数,该函数允许我从 PATH 环境变量中删除目录的重复副本。

有人告诉我,可以使用该命令通过一行命令来实现这一目标awk,但我不知道如何做到这一点。有人知道怎么做吗?

答案1

如果您在 中还没有重复项,PATH并且只想添加尚不存在的目录,则可以仅使用 shell 轻松完成此操作。

for x in /path/to/add …; do
  case ":$PATH:" in
    *":$x:"*) :;; # already there
    *) PATH="$x:$PATH";;
  esac
done

这是一个从 中删除重复项的 shell 片段$PATH。它会逐一浏览条目,并复制那些尚未看过的条目。

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

答案2

这是一个易懂的单行解决方案可以完成所有正确的事情:删除重复项,保留路径的顺序,并且不在末尾添加冒号。因此,它应该为您提供一个经过重复数据删除的 PATH,其行为与原始路径完全相同:

PATH="$(perl -e 'print join(":", grep { not $seen{$_}++ } split(/:/, $ENV{PATH}))')"

它只是在冒号 ( split(/:/, $ENV{PATH})) 上进行拆分,使用 usegrep { not $seen{$_}++ }过滤掉除第一次出现之外的任何重复路径实例,然后将剩余的路径重新连接在一起,并用冒号分隔并打印结果 ( print join(":", ...))。

如果您想要更多的结构,以及删除其他变量重复的能力,请尝试这个片段,我目前在我自己的配置中使用它:

# Deduplicate path variables
get_var () {
    eval 'printf "%s\n" "${'"$1"'}"'
}
set_var () {
    eval "$1=\"\$2\""
}
dedup_pathvar () {
    pathvar_name="$1"
    pathvar_value="$(get_var "$pathvar_name")"
    deduped_path="$(perl -e 'print join(":",grep { not $seen{$_}++ } split(/:/, $ARGV[0]))' "$pathvar_value")"
    set_var "$pathvar_name" "$deduped_path"
}
dedup_pathvar PATH
dedup_pathvar MANPATH

该代码将对 PATH 和 MANPATH 进行重复数据删除,并且您可以轻松调用保存dedup_pathvar以冒号分隔的路径列表的其他变量(例如 PYTHONPATH)。

答案3

这是一个时尚的:

printf %s "$PATH" | awk -v RS=: -v ORS=: '!arr[$0]++'

更长(看看它是如何工作的):

printf %s "$PATH" | awk -v RS=: -v ORS=: '{ if (!arr[$0]++) { print $0 } }'

好的,由于您是 Linux 新手,因此以下是如何实际设置不带尾随“:”的 PATH

PATH=`printf %s "$PATH" | awk -v RS=: '{ if (!arr[$0]++) {printf("%s%s",!ln++?"":":",$0)}}'`

顺便说一句,请确保您的 PATH 中没有包含“:”的目录,否则会弄乱。

一些功劳:

答案4

只要我们添加非 awk oneliners:

PATH=$(zsh -fc "typeset -TU P=$PATH p; echo \$P")

(可能很简单,PATH=$(zsh -fc 'typeset -U path; echo $PATH')但 zsh 总是读取至少一个zshenv配置文件,该文件可以修改PATH。)

它使用了两个很好的 zsh 功能:

  • 与数组关联的标量 ( typeset -T)
  • 以及自动删除重复值的数组 ( typeset -U)。

相关内容