行の最初または途中のパターンのGrep


9

まず、この問題は思ったよりも無害だと思います。

私が必要なこと:PATH環境変数内のフォルダーを確認します。それは最初か後のどこかにあります。そのフォルダが存在することを確認するだけです。

私の問題の例-使用しましょう/opt/gnome


シナリオ1:フォルダーがPATHの先頭にない

# echo "$PATH"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

# echo "$PATH" | grep ":/opt/gnome"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

キャッチしないように、grepは十分に具体的である必要があることに注意してください/var/opt/gnome。したがって、結腸。


シナリオ2:フォルダーがPATHの先頭にあります。

# echo "$PATH"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

# echo "$PATH" | grep "^/opt/gnome"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

これは私の問題です-このフォルダーでコロンまたは行頭を検索する必要があります。私がやりたいのは、次の2つのブラケット式の1つです。

# echo $PATH | grep "[^:]/opt/gnome"
# echo $PATH | grep "[:^]/opt/gnome"

しかし[^[:、自分の意味を持っています。したがって、上記の2つのコマンドは機能しません。

1つのコマンドでこれらの2つのシナリオをgrepできる方法はありますか?


あなたがgrepをしていないので、:コスタスの答えにジルさんのコメントがあまりにも、質問にも適用されることに注意してください/opt/gnome:または/opt/gnome$、あなたは見つけるでしょう/opt/gnome-foo/opt/gnome/bar
スコット

@スコット-間にスペースを含めて試合に参加している限り、そのような複雑さを伴うことなく、いつでも任意の文字列を行の先頭と末尾に固定できます。同様にgrep '^\(any number of other matches:*:\)*my match\(:.*\)*$'
mikeserv 2014年

回答:


10

PATHファイル内で何かを探すのではなく、環境変数の内容をチェックしている場合、それgrepは間違ったツールです。シェルで行う方が簡単です(そして、より速く、間違いなく読みやすくなっています)。

bash、ksh、zshの場合:

if [[ :$PATH: = *:/opt/gnome:* ]]; then
 : # already there
else
  PATH=$PATH:/opt/gnome
fi

ポータブル:

case :$PATH: in
  *:/opt/gnome:*) :;; # already there
  *) PATH=$PATH:/opt/gnome;;
esac

:$PATH:ではなくの使用に注意してください$PATH。このようにして、コンポーネントがの先頭または末尾にあったとしても、検索文字列では常にコロンで囲まれ$PATHます。

ファイルの行を検索する場合は、拡張正規表現(つまり、を必要とするgrep -E(^|:)/opt/gnome($|:)を使用して一致させることができますが、それが/opt/gnome行の先頭またはコロンの後ろにあり、かつ末尾のいずれかにある場合に限られます。行またはコロンが続きます。


8

使用するだけで拡張正規表現を使用できます grep -E

誤検知を回避する場合は、検索しようとしているパスの最初と最後を一致させる必要があります。

最初のインスタンスと一致します。

$ TEST=/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

中央のインスタンスにも一致します。

$ TEST=/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

誤検知の回避:

$ TEST="/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta"
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"

一致するものがありません。

コンパクトでエレガント。Debian 7でテスト済み。


1
egrepは非推奨の使用ですgrep -E(ソース:man grep
Anthon 2014

ありがとう、魅力のように動作します!しかし、私はそれを答えとして選択しませんでした。-wオプションの方が少し単純だと思うからです。私が最初に想像していたよりもさらにシンプルです!
JamesL 2014

3
警告。-wオプションでは、いくつかの問題があります。数字、文字、アンダースコアのみが「単語」と見なされます。したがって、いくつかの異常ではあるが可能な文字が原因で失敗します。例echo '/sbin:/usr/sbin:/var-/opt/gnome' | grep -w "/opt/gnome"echo '/sbin:/usr/sbin:/var./opt/gnome' | grep -w "/opt/gnome"。それらは間違った結果をもたらします。
LuisAntolínCano 2014

1
順調ですが、まだ誤検知があります:/opt/gnome/somethingelse
Gilles「SO-邪悪なことをやめなさい」2014

1
まったく正しい。最初だけでなく、最後も明示的に気にする必要があります。これで問題が解決すると思いますecho "/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta" | grep -E "(:|^)/opt/gnome(:|$)"。回答を編集しています。
LuisAntolínカノ2014

7

に慣れていない場合は、上のレコードをgrep使用awkして分離できます。:

awk 'BEGIN {RS=":"} /^\/opt\/gnome$/'

5

あなたも使うことができます

echo "$PATH" | tr ':' '\n' | grep -x "/opt/gnome"

これは、パス変数を個別の行(パスごとに1つ)に分割するgrep -xため、正確な結果を探すことができます。もちろん、これにはの追加プロセスが必要になるという欠点がありますtr。また、フォルダ名にPATH改行文字が含まれている場合は機能しません。


2

答えには十分かわかりませんが

grep -w "/opt/gnome"

あなたのニーズを満たします。

echo '/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome
echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome

だが

echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep "/opt/gnome" -o
/opt/gnome
/opt/gnome

コロンは単語以外の文字であるため、これは完全に機能します。ありがとう!
JamesL 2014

@ Sman865他の理由があります:/は単語の一部ではなく、そうrです。
Costas

2
警告。私の答えのコメントで言ったように。単語以外の文字であるディレクトリ名に有効な文字があります。それは間違った結果につながります。でディレクトリ名を終了することは通常ではありませんが、発生する可能性があります。
LuisAntolínカノ2014

4
Sman865偽陽性@: /opt/gnome-beta/home/bob/opt/gnome、...
ジル'SO-停止されて悪'

機能しないケース:grep -w /usr/local -o <<< /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games------/usr/local /usr/local /usr/local
pabouk 14年

0

選択するには、/opt/gnome非単語の文字(改行、囲まれた:/など)これを試してみてください:

grep '\B/opt/gnome'

0

これを確実に行うことができますgrep。広く利用可能であり、すでに多くのソリューションが提供されている拡張機能を利用できますが、基本的な正規表現を使用しても簡単に実行できますが、一見すると直感的ではないかもしれません。

基本的な正規表現を使用するgrepと、ラインの先頭と末尾の2つの信頼できるアンカーが常にあります。次のように、行上の位置に関係なく、これらの両方に一致をアンカーできます。

grep '^\(ignore case, delimiter\)*match\(delimiter, ignore case\)*$'

grep行の先頭から、\(grouped\)区切り文字の次に明示的な一致に出会うために必要なだけの部分式の出現と、一致の末尾から行の末尾までと同じ方法で一致します。あなたの明示的な一致が一致しない場合、明示的にそれが失敗し、何も印刷されません。

そして、あなたはそうするかもしれません、例えば:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$'

自分で見て:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$
' <<\INPUT
/opt/gnome-beta
/opt/gnome
/home/bob/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt-gnome-beta
/opt/gnomenot::::/opt/gnome
INPUT

出力

/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt/gnomenot::::/opt/gnome

0

あなたはエッジケースに気づきました...行頭にa:の出現を強制することでそれを避けることができます:

 echo ":$PATH" | grep ":/opt/gnome"

または、パスが正確である場合は、最後に1つ追加して、境界があることを確認します。

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