使用 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)。

相關內容