ファイルがあるとしましょう:
_# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
_
「foobar」の後に表示される単語を知りたいだけなので、次の正規表現を使用できます。
_"foobar \(\w\+\)"
_
括弧は、foobarの直後のWordに特別な関心があることを示しています。しかし、grep "foobar \(\w\+\)" test.txt
を実行すると、「foobarの後のWord」だけでなく、正規表現全体と一致する行全体が取得されます。
_foobar bash 1
foobar happy
_
そのコマンドの出力が次のようになっていることを強く望みます。
_bash
happy
_
正規表現のグループ(または特定のグループ)に一致するアイテムのみを出力するようにgrepに指示する方法はありますか?
GNU grepには、Perlスタイルの正規表現用の-P
オプションと、パターンに一致するものだけを出力する-o
オプションがあります。これらは、アラウンドアサーション(perlreマンページの Extended Patterns で説明)を使用して組み合わせることができ、-o
の目的で一致したと判断されたものからgrepパターンの一部を削除します。
$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$
\K
は(?<=pattern)
の短い形式(およびより効率的な形式)であり、出力するテキストの前にゼロ幅後読みアサーションとして使用します。 (?=pattern)
は、出力するテキストの後のゼロ幅先読みアサーションとして使用できます。
たとえば、foo
とbar
の間で単語を一致させたい場合は、次のように使用できます。
$ grep -oP 'foo \K\w+(?= bar)' test.txt
または(対称性のため)
$ grep -oP '(?<=foo )\w+(?= bar)' test.txt
標準のgrepではこれを行うことはできませんが、 GNU grep can)の最新バージョン を使用できます。sed、awk、またはPerlを使用できます。以下に、サンプル入力に必要なもので、まれなケースでは動作が少し異なります。
置換foobar Word other stuff
by Word
、置換が行われた場合にのみ出力します。
sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'
最初の単語がfoobar
の場合、2番目の単語を印刷します。
awk '$1 == "foobar" {print $2}'
最初の単語である場合はfoobar
を取り除き、そうでない場合はその行をスキップします。次に、最初の空白の後のすべてを取り除いて印刷します。
Perl -lne 's/^foobar\s+// or next; s/\s.*//; print'
sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p"
-n suppress printing
s substitute
^.* anything before foobar
foobar initial search match
\s* any white space character (space)
\( start capture group
\S* capture any non-white space character (Word)
\) end capture group
.*$ anything after the capture group
\1 substitute everything with the 1st capture group
p print it
まあ、foobarが常に最初のWordまたは行であることがわかっている場合は、cutを使用できます。そのようです:
grep "foobar" test.file | cut -d" " -f2
pcregrep
の方が賢い-o
オプションで、出力するキャプチャグループを選択できます。したがって、サンプルファイルを使用して、
$ pcregrep -o1 "foobar (\w+)" test.txt
bash
happy
PCREがサポートされていない場合は、grepを2回呼び出すことで同じ結果を得ることができます。たとえばfoobarの後にWordを取得するには、次のようにします。
<test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'
これは、次のようにfoobarの後に任意のWordに展開できます(読みやすくするためにEREを使用)。
i=1
<test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$'
出力:
1
インデックスi
はゼロベースであることに注意してください。
@jgshawkeyの回答はとても役に立ちました。 grep
は、これに適したツールではありませんが、sedはそうです。ただし、関連する行を取得するためにgrepを使用する例があります。
Sedの正規表現構文は、慣れていない場合は特異です。
これは別の例です:これはxinputの出力を解析してID整数を取得します
⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]
そして、私は19が欲しい
export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=\([[:digit:]]\+\).*$/\1/p")
クラスの構文に注意してください。
[[:digit:]]
そして、次のエスケープする必要性+
1行だけが一致するとします。