PATH変数から重複するエントリを削除する


9

私は頻繁に.bashrcを変更してから、それを調達しています。ただし、export PATH="~/bin:~/perl5/bin:$PATH"ファイルに次のようなものがある場合 、ファイルを読み込むPATHたびに環境変数が大きくなります。

たとえば、最初に.bashrcが読み込まれるとき、PATH変数はで構成され~/bin:~/perl5/bin:/usr/bin:/binます。

2回目はで構成され~/bin:~/perl5/bin:~/bin:~/perl5/bin:/usr/bin:/binます。

3回目は~/bin:~/perl5/bin:~/bin:~/perl5/bin:~/bin:~/perl5/bin:/usr/bin:/bin

PATHに含まれていないものを追加するだけの簡単な方法はありますか?

回答:


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
}

editzshユーザーの場合、typeset -U <variable_name>パスエントリを重複排除します。


ありがとう!それはではありません/etc/profileDebianのレニーに、私は私の中でそれを含めます.bashrc
クリストファーボトムズ

使用方法:pathmunge /some/path配置します/some/pathの初めに$PATHpathmunge /some/path after配置されます/some/pathの終わりに$PATH
クリストファー・ボトムス

HEWディレクトリは、現代のbashシェルでは、現在のパスに存在するかどうかを確認するためのチェックを行うためのクリーナー方法:if ! [[ $PATH =~ (^|:)$1($|:) ]] ; then
クリストファーキャシェル

これは使いません。私の素朴なバージョンが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つ注意すべき点は、以下を実行することです

  1. スペース文字を@文字に置き換えます
  2. 配列を分割する
  3. 配列をループする
  4. 要素文字列の@文字をスペースに置き換えます

これは、スペースを含むディレクトリを確実に処理できるようにするためです(Active Directoryユーザー名を含むSambaホームディレクトリにはスペースを含めることができます!)


警告:この実装には大きなバグがあります!! 2つのエントリが同じでなくても、正規表現が一致するため、/bin他のエントリがある場合は削除され/usr/binます。
スキマスイッチ

:ここでは代替実装その修正されるバグですgithub.com/sukima/dotfiles/blob/...
スキマスイッチ

1

パスを明示的に設定します。


ありがとう。パスを明示的に設定してみましたが、複数の環境で使用する.bashrcファイルがあるため、正確なデフォルトPATHは常に同じとは限りません。
クリストファーボトムズ

1

1つの文字列のみ:

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

ありがとう。これによって私が引き起こす困難な点の1つは、の内容をアルファベット順(またはASCII順)に並べ替えることです$PATH。特定のディレクトリを$PATH(など/home/username)の最初に配置して、組み込みのデフォルトの代わりに実行可能ファイルの個人用コピーが実行されるようにします。
クリストファーボトムズ

1

これを解決する方法は2つ考えられます。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関数を作成するのが賢明です。

注:2番目のオプションは、最新バージョンのbashで記述されている場合にのみ機能します。正規表現のサポートはBourneシェル(/ bin / sh)機能ではなく、他のシェルには存在しない場合があります。また、引用符を使用する必要がない場合や、一部の最新バージョンのbashで問題が発生する場合もあります。


ありがとう。パスを明示的に設定してみましたが、複数の環境で使用する.bashrcファイルがあるため、正確なデフォルトPATHは常に同じとは限りません。
クリストファーボトムズ

スクリプトをチェックしてローカルのホスト名を確認し、そのサーバーに合わせて絶対パスを設定することで、引き続き処理できます。
Christopher Cashell

単なるタイプミス:!にがありませんif。また、それはあなただけ言うことができるので、スペースで区切られた引数をループ関数にこれを作るのは簡単(私には)驚くほどだ:add_to_PATH ~/perl5/bin ~/.bin unix.stackexchange.com/a/4973/28760(私は推測するcase文が使用可搬性があります、しかしあなたifは私にはより明確です)。その質問がperl5を追加するという奇妙な偶然を編集してください!
2012

@ 13ren:メモをありがとう。また、必要なように二重引用符ではなく、PATHセット行で単一引用符を使用していることにも気づきました。書かれているように、それはあなたの既存のパスを変数名で置き換えます。おっとっと!どうやらそれは私にとってタイプミスの悪いエントリでした。両方が修正されました。
Christopher Cashell

0

これが私の解決策です: PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

トレーリングを残さない素敵な簡単なワンライナー:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.