GNU grep
と-P
PCRE Regexを使用して、ファイルの文字列を照合しています。入力ファイルには、次のような文字列を含む行があります。
FOO_1BAR.Zoo.2.someString:More-RandomString (string here too): 0.45654343
上記の行から2
と0.45654343
の数字をキャプチャしたいと思います。私は正規表現を使用しました
grep -Po ".Zoo.\K[\d+](.*):\ (.*)$" file
しかし、これは私に結果をもたらしています
2.someString:More-RandomString (string here too): 0.45654343
最初のキャプチャグループから最初の番号を2
として取得し、行末のキャプチャグループと照合することもできます。しかし、2つのキャプチャグループ間の単語/行をスキップすることはできません。
真ん中にそれらの単語をキャプチャしているグループ(.*)
があることは知っています。私がやろうとしたことは、それを無視する別の\K
を含めることです
grep -Po ".Zoo.\K[\d+](.*):\K (.*)$" file
しかし、それでは0.556984
として2番目のキャプチャグループしか得られませんでした。
また、(?:)
構文を使用した非キャプチャグループも
grep -Po ".Zoo.\K[\d+](?=.someString:More-RandomString (string here too)):\ (.*)$"
しかし、これは私に何も与えませんでした。ここで何が欠けていますか?
grep
の名前は、g/re/p
ed
コマンドの後に続きます。その主な目的は、正規表現に一致する行を出力することです。それらの行の内容を編集することはその役割ではありません。 sed
(ストリームエディター)またはawk
があります。
現在、GNU grep
で始まるいくつかのgrep
実装は、-o
オプションを追加して、各行の一致した部分(キャプチャグループではなく正規表現によって一致したもの)を出力します)。 GNUのようなgrep
実装(-P
を使用)または正規表現のPCREをサポートするpcregrep
を再び取得しました。
pcregrep
は実際に-o<n>
オプションを追加して、キャプチャグループのコンテンツを出力しました。だからあなたはできる:
pcregrep -o1 -o2 --om-separator=' ' '.Zoo.(\d+).*:\s+(.*)'
しかし、ここでは、明らかな標準的な解決策はsed
を使用することです。
sed -n 's/^.*\.Zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'
または、Perl正規表現が必要な場合は、Perlを使用します。
Perl -lne 'print "$1 $2" if /\.Zoo\.(\d+).*:\s+(.*)/'
GNU grep
を使用すると、一致が別の行に表示されることを気にしない場合は、次のことができます。
$ grep -Po '\.Zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343
\K
は一致した部分の開始をリセットしますが、これは、交互の2つの部分が重なり合うことで回避できるという意味ではありません。
grep -Po '.Zoo。(\ K\d + | .:\ K。)'
echo foobar | grep -Po 'foo|foob'
が機能しないように機能しません(foo
とfoob
の両方を出力する場合)。 foo|foob
は、最初にfoo
に一致し、次にgrep
は、foo
の後の入力で他の潜在的な一致を探します。つまり、b
のbar
から開始するため、それ以降は検索できません。
上記のgrep -Po '\.Zoo\.\K\d+|:\s+\K.*'
では、代替の2番目の部分で:<spaces><anything>
のみが検索されます。これは.Zoo.<digits>
の後の部分で一致しますが、:<spaces><anything>
の後に続くときだけでなく、入力内のどこでも.Zoo.<digits>
を見つけることを意味します。
ただし、別のPCRE特殊演算子\G
を使用して、これを回避する方法があります。 \G
は件名の先頭で一致します。単一の一致の場合、これは^
と同等ですが、複数の一致がある場合(s/.../.../g
のsed
/Perl
のg
フラグを考えてください)、-o
と同様に、grep
が行は、前の一致の終了後にも一致します。だからそれを作ったら:
grep -Po '\.Zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
ここで、(?!^)
は行の先頭ではないを意味する否定的な先読み演算子であり、\G
は前回の(空でない)一致が成功した後にのみ一致します。したがって、.*:\s+\K.*
は、前の一致が成功した場合にのみ一致します。代替のその他の部分は行の終わりまで一致するため、これは.foo.<digits>
の1つにすぎません。
次のような入力で:
.Zoo.1.Zoo.2 tar: blah
それは出力します:
1
2
blah
でも。それを望まなかった場合は、代替の最初の部分も行の先頭でのみ一致させる必要があります。何かのようなもの
grep -Po '^.*?\.Zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
それでも、2
や.Zoo.2 no colon character
などの入力では.Zoo.2 blah:
が出力されます。代替の最初の部分で先読み演算子を使用して回避し、:<spaces>
の後に少なくとも1つの非スペースを探す(および$
を使用して非文字の問題を回避する) )
grep -Po '^.*?\.Zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'
おそらく、その正規表現を説明するために数ページのコメントが必要になるでしょう。そのため、私はまっすぐ進むsed
/Perl
ソリューションを探します...