あるファイルがあるとします。
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
私は、"foobar"の後に現れる単語を知りたいだけなので、この正規表現を使うことができます。
"foobar \(\w\+\)"
括弧は、foobarの直後の単語に特別な関心を持っていることを示しています。 しかし、grep "foobar \(w\+\)" test.txt
とすると、"the word after foobar"だけではなく、正規表現全体にマッチした行全体が表示されます。
foobar bash 1
foobar happy
私は、このコマンドの出力が次のようになることを望んでいます。
bash
happy
正規表現のグルーピング(または特定のグルーピング)にマッチする項目のみを出力するようにgrepに指示する方法はありますか?
GNU grepには、perlスタイルの正規表現のための-P
オプションと、パターンにマッチしたものだけを表示する-o
オプションがあります。これらは、ルックアラウンドアサーション(perlre manpageの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の最近のバージョンではできます。sed, awk, perlを使うこともできます。ここでは、あなたのサンプル入力に対して望むことを行ういくつかの例を紹介します。
foobar word other stuffを
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'