awkコマンドを使用して重複した$PATHエントリを削除する

awkコマンドを使用して重複した$PATHエントリを削除する

PATH環境変数からディレクトリの重複コピーを削除できるbashシェル関数を作成しようとしています。

私はこのコマンドを使って1行のコマンドでこれを行うことができると言われましたが、awkどうすればいいのかわかりません。これを行う方法を知っている人はいますか?

答え1

まだ重複エントリがなく、PATHまだ存在しないディレクトリを追加する場合は、シェルのみを使用して簡単にこれを行うことができます。

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

以下は、重複エントリが削除されるシェルの断片です$PATH。項目を 1 つずつ見て、まだ表示されていない項目をコピーします。

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})コロン()に分割し、useを使用して最初のgrep { 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ではなくonelinerを追加する限り:

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

(簡単かもしれませんが、zshは常に変更できる少なくともPATH=$(zsh -fc 'typeset -U path; echo $PATH')1つの設定ファイルを読み込みます。)zshenvPATH

2つの素晴らしいzsh機能を使用します。

  • 配列に関連するスカラー( typeset -T)
  • 重複した値を自動的に削除する配列(typeset -U)。

関連情報