Bashの$ PATH変数からパスを削除する最もエレガントな方法は何ですか?


114

より一般的には、Bash環境変数のコロンで区切られたリストからアイテムを削除するにはどうすればよいですか?

数年前に、より高度な形式のBash変数展開を使用する簡単な方法を見たと思ったのですが、そうだとすればそれを見失ってしまいました。Googleをすばやく検索したところ、関連する結果は驚くほど少なく、私が「シンプル」または「エレガント」と呼ぶものは見つかりませんでした。たとえば、sedとawkをそれぞれ使用する2つのメソッド:

PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)

簡単なものは何もありませんか?Bashのsplit()関数に類似したものはありますか?

更新:
わざとあいまいな質問をお詫びする必要があるようです。私は特定のユースケースを解決することよりも、良い議論を引き起こすことに関心がありませんでした。幸い、私はそれを手に入れました!

ここにはいくつかの非常に巧妙なテクニックがあります。最後に、ツールボックスに次の3つの関数を追加しました。マジックはpath_removeで発生します。これは、主にMartin YorkのawkRS変数の巧妙な使用に基づいています。

path_append ()  { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove ()  { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }

唯一の本当の残骸はsed、末尾のコロンを削除するための使用です。マーティンの残りの解決策がどれほど単純であるかを考えると、私はそれと共存することを非常に望んでいます!


関連する質問: シェルスクリプトで$ PATH要素を操作するにはどうすればよいですか?


任意の変数の場合:(@ martin-yorkおよび@ andrew-aylettに基づいて)次のWORK=`echo -n ${1} | awk -v RS=: -v ORS=: '$0 != "'${3}'"' | sed 's/:$//'`; eval "export ${2}=${WORK}"ように呼び出す必要がありますfunc $VAR VAR pattern
vesperto

回答:


51

awkの1分:

# Strip all paths with SDE in them.
#
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'`

編集:それは以下のコメントに応答します:

$ export a="/a/b/c/d/e:/a/b/c/d/g/k/i:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i"
$ echo ${a}
/a/b/c/d/e:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i

## Remove multiple (any directory with a: all of them)
$ echo ${a} | awk -v RS=: -v ORS=: '/a/ {next} {print}'
## Works fine all removed

## Remove multiple including last two: (any directory with g)
$ echo ${a} | awk -v RS=: -v ORS=: '/g/ {next} {print}'
/a/b/c/d/e:/a/b/c/d/f:
## Works fine: Again!

セキュリティの問題に応じて編集する:(これは質問には関係ありません)

export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//')

これにより、最後のエントリを削除することによって残っているコロンがすべて削除さ.れ、パスに効果的に追加されます。


1
最後の要素または複数の要素を削除しようとすると失敗します。最初のケースでは、現在のディレクトリが(空の文字列として、潜在的なセキュリティホールとして)追加され、2番目のケースでは、パス要素として ``が追加されます。
Fred Foo

1
@larsmans:私にとってはうまくいきます。注:空は「./」である現在のディレクトリと同じではありません
Martin York

2
PATH変数の「メンバー」としての空の文字列、特別な規則として、少なくとも1979年のV7 Unix以降のすべてのUnixシェルの現在のディレクトリを示していbashます。マニュアルを確認するか、自分で試してください。
Fred Foo

1
@Martin:POSIXはこの動作を必要としませんが、それを文書と認めていません:pubs.opengroup.org/onlinepubs/9699919799/basedefs/...
フレッド・フー

1
これで最後の要素を削除すると、さらに微妙な問題が発生します。awkは、文字列の最後にnullバイトを追加するようです。つまり、後で別のディレクトリをPATHに追加しても、実際には検索されません。
2012年

55

私の汚いハック:

echo ${PATH} > t1
vi t1
export PATH=$(cat t1)

18
最も明白な解決策をしているとき、それは良い兆候ことはない -automateプロセスを。:-D
ベンブランク

「エレガント」な選択肢よりもはるかに安全です。
Jortstek

44

置換の大きな問題はエンドケースなので、エンドケースを他のケースと同じにしてみてはどうでしょうか。パスの先頭と末尾に既にコロンが付いている場合は、コロンで囲まれた目的の文字列を検索するだけです。そのままでは、これらのコロンを簡単に追加し、後で削除できます。

# PATH => /bin:/opt/a dir/bin:/sbin
WORK=:$PATH:
# WORK => :/bin:/opt/a dir/bin:/sbin:
REMOVE='/opt/a dir/bin'
WORK=${WORK/:$REMOVE:/:}
# WORK => :/bin:/sbin:
WORK=${WORK%:}
WORK=${WORK#:}
PATH=$WORK
# PATH => /bin:/sbin

純粋なbash :)。


2
追加のフロスティングのために、このチュートリアルセクションを追加します:tldp.org/LDP/abs/html/string-manipulation.html
Cyber​​ Oliveira

1
最も簡単な解決策のように見えたので、これを使用しました。これは非常に高速で簡単で、実際にPATH変数を変更する最後の行の直前にecho $ WORKを使用して作業を簡単に確認できます。
Phil Gran

2
絶対にちょっとした逸品。この投稿を見つけたとき、まさに私がやろうとしていたこと。-アンドリュー、ありがとう!ところで、スペース(「/ usr / bin」と同じ)と最後の行「$ WORK」を含める必要がある場合に備えて、「:$ PATH:」を二重引用符で囲みます。

2
ありがとう、@ PacMan-- :) 私はかなり確信している(ちょうどそれを試してみました)にアサインメントのためのスペースを必要としないWORKPATH行が変数の代入やコマンド実行のためのセクションに解析された後、変数の展開が起こるように。 REMOVE引用符で囲む必要がある場合や、定数の場合は、文字列をそのまま置換に含めることができます。
Andrew Aylett、

文字列が保存されたときはいつも混乱していたので、文字列を常に二重引用符で囲み始めました。これを明確にしてくれてありがとう。:)

26

これが私が考案できる最も簡単な解決策です:

#!/bin/bash
IFS=:
# convert it to an array
t=($PATH)
unset IFS
# perform any array operations to remove elements from the array
t=(${t[@]%%*usr*})
IFS=:
# output the new array
echo "${t[*]}"

上記の例は、 "usr"を含む$ PATHの要素をすべて削除します。「* usr *」を「/ home / user / bin」に置き換えて、その要素のみを削除できます。

sschuberthごとの更新

私はにスペースが思うにもかかわらず、$PATHある恐ろしいアイデア、ここでハンドルをそのソリューションです:

PATH=$(IFS=':';t=($PATH);n=${#t[*]};a=();for ((i=0;i<n;i++)); do p="${t[i]%%*usr*}"; [ "${p}" ] && a[i]="${p}"; done;echo "${a[*]}");

または

IFS=':'
t=($PATH)
n=${#t[*]}
a=()
for ((i=0;i<n;i++)); do
  p="${t[i]%%*usr*}"
  [ "${p}" ] && a[i]="${p}"
done
echo "${a[*]}"

2
1つのライナーとして:PATH = $(IFS = ':'; t =($ PATH); unset IFS; t =($ {t [@] %% * usr *}); IFS = ':'; echo "$ {t [*]} ");
nicerobot 2008

1
このソリューションは、スペースを含むPATHのパスでは機能しません。コロンで置き換えます。
2012年

11

現在受け入れられている最も高い評価の回答にもかかわらず、PATHに非表示の文字を追加せず、スペースを含むパスに対処できるワンライナーは次のとおりです。

export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/cygwin/" | tr "\n" ":"); echo ${p%:})

個人的には、これも読みやすく、理解しやすいと思います。これには、awkを使用する代わりに、一般的なコマンドのみが含まれます。


2
:あなたがファイル名に改行しても、対応できる何かをしたい場合は...と、あなたはこれを使用することができます export PATH=$(p=$(echo $PATH | tr ":" "\0" | grep -v -z "/cygwin/" | tr "\0" ":"); echo ${p%:}) (間違いなくかかわらず、あなたが行う場合は:)、これを必要とする理由、あなたは自問する場合があります)
ehdr

これにより、部分一致が削除されます。使用するgrep -v "^/path/to/remove\$"grep -v -x "/path/to/remove"
ShadSterling

良い解決策ですが、あなたは本当にtrより一般的だと思いますawkか?;)
K.-Michael Aye

1
もちろんです。WindowsのGit Bashなどの軽量環境には、のようなtrインタープリターではなく、単純なツールが付属していawkます。
sschuberth

1
@ehdr:などのパスで機​​能するにecho "..."printf "%s" "..."、で置き換える必要が-eあります。stackoverflow.com/a/49418406/102441
Eric

8

以下がその解決策です。

  • 純粋なバッシュです
  • 他のプロセス(「sed」や「awk」など)を呼び出さない、
  • 変わらないIFS
  • サブシェルをフォークしません、
  • スペースを含むパスを処理し、
  • 内のすべての引数を削除しPATHます。

    removeFromPath(){
       ローカルpd
       p = ":$ 1:"
       d = ":$ PATH:"
       d = $ {d // $ p /:}
       d = $ {d /#:/}
       PATH = $ {d /%:/}
    }

4
私はこのソリューションが好きです。たぶん変数名をよりわかりやすくしますか?
Anukool 2015年

非常に素晴らしい。ただし、アスタリスク(*)を含むパスセグメントでは機能しません。時々彼らは偶然そこに着く。
ヨルク

6

function __path_remove(){
local D = ":$ {PATH}:";
["$ {D /:$ 1:/:}"!= "$ D"] && PATH = "$ {D /:$ 1:/:}";
PATH = "$ {PATH /#:/}";
エクスポートPATH = "$ {PATH /%:/}";
}

.bashrcファイルからそれを掘り出します。PATHをいじると、パスが失われると、awk / sed / grepが利用できなくなります:-)


1
それは非常に良い点です。(私はこのような単純なもののために外部ユーティリティを実行するのが好きではありませんでした)。

6

これまでに見つけた最も純粋なbashオプションは次のとおりです。

function path_remove {
  PATH=${PATH/":$1"/} # delete any instances in the middle or at the end
  PATH=${PATH/"$1:"/} # delete any instances at the beginning
}

これは、スーパーユーザーにまだ存在していない場合、ディレクトリを$ PATH追加するという、正しくない回答に基づいています


これも結構いいです。私はそれをテストしました。PATHに重複するパス(例:まったく同じ2つ)がある場合、そのうちの1つだけが削除されます。ワンライナーにすることもできます:removePath () { PATH=${PATH/":$1"/}; PATH=${PATH/"$1:"/}; }

このソリューション$PATHは、ターゲット(つまり削除される)パスのサブフォルダがに含まれている場合は失敗します。例:a:abc/def/bin:b-> a/bin:b、いつabc/def削除するか。
Robin Hsu

5

私はbashディストリビューションの関数を使用してきましたが、1991年以降明らかにそうです。これらはまだFedoraのbash-docsパッケージにあり、以前はで使用されて/etc/profileいましたが、それ以上...

$ rpm -ql bash-doc |grep pathfunc
/usr/share/doc/bash-4.2.20/examples/functions/pathfuncs
$ cat $(!!)
cat $(rpm -ql bash-doc |grep pathfunc)
#From: "Simon J. Gerraty" <sjg@zen.void.oz.au>
#Message-Id: <199510091130.VAA01188@zen.void.oz.au>
#Subject: Re: a shell idea?
#Date: Mon, 09 Oct 1995 21:30:20 +1000


# NAME:
#       add_path.sh - add dir to path
#
# DESCRIPTION:
#       These functions originated in /etc/profile and ksh.kshrc, but
#       are more useful in a separate file.
#
# SEE ALSO:
#       /etc/profile
#
# AUTHOR:
#       Simon J. Gerraty <sjg@zen.void.oz.au>

#       @(#)Copyright (c) 1991 Simon J. Gerraty
#
#       This file is provided in the hope that it will
#       be of use.  There is absolutely NO WARRANTY.
#       Permission to copy, redistribute or otherwise
#       use this file is hereby granted provided that
#       the above copyright notice and this notice are
#       left intact.

# is $1 missing from $2 (or PATH) ?
no_path() {
        eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

4

これに対する答えをここに書きました(awkも使用)。しかし、それがあなたが探しているものかどうかわかりませんか?1行に収めようとするのではなく、少なくともそれが何をするのか私には明らかに見えます。シンプルなワンライナーの場合は、物を取り除くだけなので、お勧めします

echo $PATH | tr ':' '\n' | awk '$0 != "/bin"' | paste -sd:

交換は

echo $PATH | tr ':' '\n' | 
    awk '$0 != "/bin"; $0 == "/bin" { print "/bar" }' | paste -sd:

または(短いが読みにくい)

echo $PATH | tr ':' '\n' | awk '$0 == "/bin" { print "/bar"; next } 1' | paste -sd:

とにかく、同じ質問、および多くの役立つ回答については、こちらを参照してください


また、部分的な文字列を含む行を削除する場合は、を使用しますawk '$0 !~ "/bin"'。つまり、awk演算子を使用して、「/ bin」を含まない行を保持します!~
thoni56

3

まあ、bashでは、正規表現をサポートしているので、次のようにします。

PATH=${PATH/:\/home\/user\/bin/}

正規表現ではなく、パス名の展開だけではないですか?
dreamlax 2008

2
bashは正規表現をサポートしていますが(bash 3以降)、これはその例ではなく、変数置換です。
Robert Gamble

4
これはパターン変数拡張であり、解決策にはいくつかの問題があります。1)最初の要素と一致しません。2)「/ home / user / bin」だけでなく、「/ home / user / bin」で始まるすべてに一致します。3)特殊文字をエスケープする必要があります。せいぜい、これは不完全な例だと思います。
nicerobot 2008

2

@BenBlankの元の質問に対する更新に示されている3つの関数が好きです。それらを一般化するために、私は2引数形式を使用します。これにより、PATHまたは必要なその他の環境変数を設定できます。

path_append ()  { path_remove $1 $2; export $1="${!1}:$2"; }
path_prepend () { path_remove $1 $2; export $1="$2:${!1}"; }
path_remove ()  { export $1="`echo -n ${!1} | awk -v RS=: -v ORS=: '$1 != "'$2'"' | sed 's/:$//'`"; }

使用例:

path_prepend PATH /usr/local/bin
path_append PERL5LIB "$DEVELOPMENT_HOME/p5/src/perlmods"

スペースを含むパス名を適切に処理できるように、引用符もいくつか追加したことに注意してください。


2

Bashの$ PATH変数からパスを削除する最もエレガントな方法は何ですか?

awkよりもエレガントなものは何ですか?

path_remove ()  { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; 

Python!これは、より読みやすく保守しやすいソリューションであり、実際に目的どおりに動作していることを確認するのは簡単です。

最初のパス要素を削除したいとしますか?

PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"

(代わりの配管echoos.getenv['PATH']少し短くなり、かつ上記と同じ結果を提供するが、それはあなたが気に環境から直接パイプにおそらく最高ですので、私は、Pythonはその環境変数を使用して何かをするかもしれないと心配しています。)

同様に最後から削除するには:

PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"

これらの再利用可能なシェル関数を作成するには、たとえば、.bashrcファイルを挿入します。

strip_path_first () {
    PATH="$(echo "$PATH" | 
    python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"
}

strip_path_last () {
    PATH="$(echo "$PATH" | 
    python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"
}

1

はい、たとえば、PATHの最後にコロンを置くと、パスを削除するのが不便でエラーが発生しやすくなります。

path_remove ()  { 
   declare i newPATH
   newPATH="${PATH}:"
   for ((i=1; i<=${#@}; i++ )); do
      #echo ${@:${i}:1}
      newPATH="${newPATH//${@:${i}:1}:/}" 
   done
   export PATH="${newPATH%:}" 
   return 0; 
} 

path_remove_all ()  {
   declare i newPATH
   shopt -s extglob
   newPATH="${PATH}:"
   for ((i=1; i<=${#@}; i++ )); do
      newPATH="${newPATH//+(${@:${i}:1})*([^:]):/}" 
      #newPATH="${newPATH//+(${@:${i}:1})*([^:])+(:)/}" 
   done
   shopt -u extglob 
   export PATH="${newPATH%:}" 
   return 0 
} 

path_remove /opt/local/bin /usr/local/bin

path_remove_all /opt/local /usr/local 

1

$ PATHで重複を削除することに不安がある場合、最も洗練された方法であるIMHOは、最初にそれらを追加しないことです。1行で:

if ! $( echo "$PATH" | tr ":" "\n" | grep -qx "$folder" ) ; then PATH=$PATH:$folder ; fi

$ folderは何にでも置き換えることができ、スペースを含めることができます( "/ home / user / my documents")


1

私がこれまでに見つけた最もエレガントな純粋なbashソリューション:

pathrm () {                                                                      
  local IFS=':'                                                                  
  local newpath                                                                  
  local dir                                                                      
  local pathvar=${2:-PATH}                                                       
  for dir in ${!pathvar} ; do                                                    
    if [ "$dir" != "$1" ] ; then                                                 
      newpath=${newpath:+$newpath:}$dir                                          
    fi                                                                           
  done                                                                           
  export $pathvar="$newpath"                                                        
}

pathprepend () {                                                                 
  pathrm $1 $2                                                                   
  local pathvar=${2:-PATH}                                                       
  export $pathvar="$1${!pathvar:+:${!pathvar}}"                                  
}

pathappend () {                                                                    
  pathrm $1 $2                                                                   
  local pathvar=${2:-PATH}                                                       
  export $pathvar="${!pathvar:+${!pathvar}:}$1"                                  
} 

1

他の提案ソリューションのほとんどは、特別な名前が好き含むパスセグメントの文字列マッチングにのみ依存していると考慮されていない...またはを~。以下のbash関数は、引数とパスセグメントのディレクトリ文字列を解決して、論理ディレクトリの一致と文字列の一致を検索します。

rm_from_path() {
  pattern="${1}"
  dir=''
  [ -d "${pattern}" ] && dir="$(cd ${pattern} && pwd)"  # resolve to absolute path

  new_path=''
  IFS0=${IFS}
  IFS=':'
  for segment in ${PATH}; do
    if [[ ${segment} == ${pattern} ]]; then             # string match
      continue
    elif [[ -n ${dir} && -d ${segment} ]]; then
      segment="$(cd ${segment} && pwd)"                 # resolve to absolute path
      if [[ ${segment} == ${dir} ]]; then               # logical directory match
        continue
      fi
    fi
    new_path="${new_path}${IFS}${segment}"
  done
  new_path="${new_path/#${IFS}/}"                       # remove leading colon, if any
  IFS=${IFS0}

  export PATH=${new_path}
}

テスト:

$ mkdir -p ~/foo/bar/baz ~/foo/bar/bif ~/foo/boo/bang
$ PATH0=${PATH}
$ PATH=~/foo/bar/baz/.././../boo/././../bar:${PATH}  # add dir with special names
$ rm_from_path ~/foo/boo/../bar/.  # remove same dir with different special names
$ [ ${PATH} == ${PATH0} ] && echo 'PASS' || echo 'FAIL'

さらに、ボックスの外側に1つ
マーティンヨーク

1

Linux from Scratchは、次の3つのBash関数を定義してい/etc/profileます。

# Functions to help us manage paths.  Second argument is the name of the
# path variable to be modified (default: PATH)
pathremove () {
        local IFS=':'
        local NEWPATH
        local DIR
        local PATHVARIABLE=${2:-PATH}
        for DIR in ${!PATHVARIABLE} ; do
                if [ "$DIR" != "$1" ] ; then
                  NEWPATH=${NEWPATH:+$NEWPATH:}$DIR
                fi
        done
        export $PATHVARIABLE="$NEWPATH"
}

pathprepend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"
}

pathappend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"
}

export -f pathremove pathprepend pathappend

参照:http : //www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html


1

私はこの質問が誰もが好むBASHについて尋ねることを知っていますが、私は対称性を楽しんでおり、時には「csh」を使用する必要があるため、「path_prepend()」、「path_append()」および「path_remove」に相当するものを作成しました() "上記のエレガントなソリューション。

要点は、「csh」には関数がないため、関数のように機能する小さなシェルスクリプトを個人用のbinディレクトリに配置したことです。指定した環境変数を変更するために、これらのスクリプトをSOURCEするエイリアスを作成します。

〜/ bin / _path_remove.csh:

set _resolve = `eval echo $2`
setenv $1 `eval echo -n \$$1 | awk -v RS=: -v ORS=: '$1 != "'${_resolve}'"' | sed 's/:$//'`;
unset _resolve

〜/ bin / _path_append.csh:

source ~/bin/_path_remove.csh $1 $2
set _base = `eval echo \$$1`
set _resolve = `eval echo $2`
setenv $1 ${_base}:${_resolve}
unset _base _resolve

〜/ bin / _path_prepend.csh:

source ~/bin/_path_remove.csh $1 $2
set _base = `eval echo \$$1`
set _resolve = `eval echo $2`
setenv $1 ${_resolve}:${_base}
unset _base _resolve

〜/ bin / .cshrc:


alias path_remove  "source ~/bin/_path_remove.csh  '\!:1' '\!:2'"
alias path_append  "source ~/bin/_path_append.csh  '\!:1' '\!:2'"
alias path_prepend "source ~/bin/_path_prepend.csh '\!:1' '\!:2'"

あなたはこのようにそれらを使うことができます...

%(csh)> path_append MODULEPATH ${HOME}/modulefiles

0

エレガントな方法がないように、これはかなり問題になる傾向があるので、ソリューションを再配置して問題を回避することをお勧めします。PATHを破壊しようとするのではなく、構築してください。

私はあなたの本当の問題のコンテキストを知っていれば、より具体的になる可能性があります。当面は、ソフトウェアビルドをコンテキストとして使用します。

ソフトウェアのビルドに関する一般的な問題は、一部のマシンでは、最終的に誰かがデフォルトのシェル(PATHおよびその他の環境変数)をどのように構成したかにより、壊れるということです。エレガントなソリューションは、シェル環境を完全に指定することにより、ビルドスクリプトを無効にすることです。ビルドスクリプトをコーディングして、コンパイラー、ライブラリー、ツール、コンポーネントなどの場所など、ユーザーが制御する組み立て部分に基づいてPATHおよびその他の環境変数を設定します。次に、スクリプトで適切に使用します。

たとえば、新しい雇用主で継承した、MavenベースのWebLogicターゲットJavaビルドがあります。ビルドスクリプトは壊れやすいことで有名で、別の新入社員と私は3週間(フルタイムではなく、あちこちにありますが、それでも何時間も)を使ってマシンで作業しました。重要なステップは、PATHを制御して、どのJava、どのMaven、およびどのWebLogicが呼び出されているかを正確に把握することでした。これらの各ツールを指す環境変数を作成し、それらに加えていくつかのツールに基づいてPATHを計算しました。最後に再現可能なビルドを作成するまで、同様の手法で他の構成可能な設定を調整しました。

ちなみに、Mavenを使用しないでください。Javaは大丈夫です。クラスタリングが絶対に必要な場合にのみWebLogicを購入してください(ただし、それ以外の場合は、特に独自の機能は必要ありません)。

ご多幸を祈る。


rootアクセス権がなく、管理者がを管理する場合がありますPATH。もちろん、自分で作成することもできますが、管理者が何かを移動するたびに、管理者がそれをどこに置いたかを把握する必要があります。そのようなことは、管理者を持つという目的に反します。
Shep、

0

@litbと同様に、「シェルスクリプトで$ PATH要素を操作するにはどうすればよいですか?」という質問への回答を提供したので、私の主な答えはそこにあります。

bashおよびその他のBourneシェルデリバティブの「分割」機能は、$IFSフィールド間セパレータであるで最も適切に実現されます。例えば、位置引数(設定するには$1$2PATH、使用の要素には、...):

set -- $(IFS=":"; echo "$PATH")

$ PATHにスペースがない限り、問題なく動作します。スペースを含むパス要素で機能させるのは簡単なことではありません-興味のある読者に任せてください。Perlなどのスクリプト言語を使用して処理する方がおそらく簡単です。

またclnpath、PATHの設定に広範囲に使用するスクリプトも持っています。「cshでPATH変数が重複しないようにする方法」の回答に記載しました。


IFS =:a =($ PATH); IFS =分割もいいです。スペースも含まれている場合に機能します。しかし、あなたは配列を得て、名前を削除するためにforループなどをいじる必要があります。
Johannes Schaub-litb 2008

はい; 面倒です-私の更新されたコメントと同様に、現時点ではスクリプト言語を使用する方がおそらく簡単です。
ジョナサンレフラー

0

この問題を苛立たせているのは、最初と最後の要素の間のフェンスポストのケースです。問題はIFSを変更して配列を使用することでエレガントに解決できますが、パスが配列形式に変換された後にコロンを再導入する方法がわかりません。

これは、$PATH文字列操作のみを使用することから1つのディレクトリを削除する、やや洗練されていないバージョンです。私はそれをテストしました。

#!/bin/bash
#
#   remove_from_path dirname
#
#   removes $1 from user's $PATH

if [ $# -ne 1 ]; then
  echo "Usage: $0 pathname" 1>&2; exit 1;
fi

delendum="$1"
NEWPATH=
xxx="$IFS"
IFS=":"
for i in $PATH ; do
  IFS="$xxx"
  case "$i" in
    "$delendum") ;; # do nothing
    *) [ -z "$NEWPATH" ] && NEWPATH="$i" || NEWPATH="$NEWPATH:$i" ;;
  esac
done

PATH="$NEWPATH"
echo "$PATH"

0

これがPerlのワンライナーです:

PATH=`perl -e '$a=shift;$_=$ENV{PATH};s#:$a(:)|^$a:|:$a$#$1#;print' /home/usr/bin`

$a変数を削除するパスを取得します。s(代替)とprintコマンドが暗黙のうちに操作する$_変数。


0

ここに良いもの。私はこれを使って、そもそもデュープを追加しないようにしています。

#!/bin/bash
#
######################################################################################
#
# Allows a list of additions to PATH with no dupes
# 
# Patch code below into your $HOME/.bashrc file or where it
# will be seen at login.
#
# Can also be made executable and run as-is.
#
######################################################################################

# add2path=($HOME/bin .)                  ## uncomment space separated list 
if [ $add2path ]; then                    ## skip if list empty or commented out
for nodup in ${add2path[*]}
do
    case $PATH in                 ## case block thanks to MIKE511
    $nodup:* | *:$nodup:* | *:$nodup ) ;;    ## if found, do nothing
    *) PATH=$PATH:$nodup          ## else, add it to end of PATH or
    esac                          ## *) PATH=$nodup:$PATH   prepend to front
done
export PATH
fi
## debug add2path
echo
echo " PATH == $PATH"
echo

1
あなたはパス文字列を先頭と末尾にコロンを追加することによって、あなたのケース文を簡素化することができます:case ":$PATH:" in (*:"$nodup":*) ;; (*) PATH="$PATH:$nodup" ;; esac
グレンはジャックマン

0

拡張グロビングを有効にすると、次のことが可能になります。

# delete all /opt/local paths in PATH
shopt -s extglob 
printf "%s\n" "${PATH}" | tr ':' '\n' | nl
printf "%s\n" "${PATH//+(\/opt\/local\/)+([^:])?(:)/}" | tr ':' '\n' | nl 

man bash | less -p extglob

0

拡張グロビングワンライナー(まあ、一種):

path_remove ()  { shopt -s extglob; PATH="${PATH//+(${1})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 

$ 1でスラッシュをエスケープする必要はないようです。

path_remove ()  { shopt -s extglob; declare escArg="${1//\//\\/}"; PATH="${PATH//+(${escArg})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 

0

PATHにコロンを追加すると、次のようなこともできます。

path_remove ()  { 
   declare i newPATH
   # put a colon at the beginning & end AND double each colon in-between
   newPATH=":${PATH//:/::}:"   
   for ((i=1; i<=${#@}; i++)); do
       #echo ${@:${i}:1}
       newPATH="${newPATH//:${@:${i}:1}:/}"   # s/:\/fullpath://g
   done
   newPATH="${newPATH//::/:}"
   newPATH="${newPATH#:}"      # remove leading colon
   newPATH="${newPATH%:}"      # remove trailing colon
   unset PATH 
   PATH="${newPATH}" 
   export PATH
   return 0 
} 


path_remove_all ()  {
   declare i newPATH extglobVar
   extglobVar=0
   # enable extended globbing if necessary
   [[ ! $(shopt -q extglob) ]]  && { shopt -s extglob; extglobVar=1; }
   newPATH=":${PATH}:"
   for ((i=1; i<=${#@}; i++ )); do
      newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}"     # s/:\/path[^:]*//g
   done
   newPATH="${newPATH#:}"      # remove leading colon
   newPATH="${newPATH%:}"      # remove trailing colon
   # disable extended globbing if it was enabled in this function
   [[ $extglobVar -eq 1 ]] && shopt -u extglob
   unset PATH 
   PATH="${newPATH}" 
   export PATH
   return 0 
} 

path_remove /opt/local/bin /usr/local/bin

path_remove_all /opt/local /usr/local 

0

path_remove_all(proxxyによる):

-newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" 
+newPATH="${newPATH//:${@:${i}:1}*([^:])/}"        # s/:\/path[^:]*//g 

0

これは非常に古いスレッドですが、この解決策は興味深いかもしれないと思いました:

PATH="/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
REMOVE="ccache" # whole or part of a path :)
export PATH=$(IFS=':';p=($PATH);unset IFS;p=(${p[@]%%$REMOVE});IFS=':';echo "${p[*]}";unset IFS)
echo $PATH # outputs /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

このブログ投稿で見つけました。私はこれが一番好きだと思います:)


0

私はここにいるほとんどの人とは少し異なるアプローチをとり、特に文字列操作だけに焦点を合わせました。

path_remove () {
    if [[ ":$PATH:" == *":$1:"* ]]; then
        local dirs=":$PATH:"
        dirs=${dirs/:$1:/:}
        export PATH="$(__path_clean $dirs)"
    fi
}
__path_clean () {
    local dirs=${1%?}
    echo ${dirs#?}
}

上記は、私が使用する最終的な関数の簡単な例です。私も作成path_add_beforeしましたpath_add_afterあなたはすでにPATHで指定したパスの後に/前にパスを挿入可能。

関数の完全なセットは、私のdotfilesのpath_helpers.shで利用できます。それらは、PATH文字列の先頭/中間/末尾での削除/追加/前置/挿入を完全にサポートします。

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