複数行の grep は、別のファイルが表示されるたびに検索します。

複数行の grep は、別のファイルが表示されるたびに検索します。

次のファイルがあります。

はい.txt

    -1
    15
         1         0         0        11 -1.0000E+001  1.0000E+001 -1.0000E+001
         2         0         0        11  1.0000E+001  1.0000E+001 -1.0000E+001
...
        29         0         0        11  1.0000E+001  2.0000E+001  1.0000E+001
        30         0         0        11  5.0000E+000  5.0000E+000  5.0000E+000
    -1
 
#ffafsda
    -1
    780
         1       116         1         2         1         1         7        20
         1        11         2        15         4        18         3        12
        13        16        22        19         5        24         9        29
         8        27         6        23
    -1
    
    asfasd
    
    afsdasdf

常に正確に一致する行で始まり終わるブロックで構成されています^ {4}-1$。このチャンクでファイルを複数に分割する必要があります。

私が今考えているのは、これらの塊を抽出する複数行の正規表現です。

grep -Pzo '(?s)((?m:^)\s{4}-1(?m:$).*?(?m:^)\s{4}-1(?m:$))' example.txt

出力:

    -1
    15
         1         0         0        11 -1.0000E+001  1.0000E+001 -1.0000E+001
         2         0         0        11  1.0000E+001  1.0000E+001 -1.0000E+001
...
        29         0         0        11  1.0000E+001  2.0000E+001  1.0000E+001
        30         0         0        11  5.0000E+000  5.0000E+000  5.0000E+000
    -1    -1
    780
         1       116         1         2         1         1         7        20
         1        11         2        15         4        18         3        12
        13        16        22        19         5        24         9        29
         8        27         6        23
    -1

2番目の一致は、最初の一致の後に正確に印刷されることがあります(改行や区切り文字なし)。これらのイベントをファイルに分割することはできません。

希望の出力は次のとおりです。

ファイル1:

    -1
    15
         1         0         0        11 -1.0000E+001  1.0000E+001 -1.0000E+001
         2         0         0        11  1.0000E+001  1.0000E+001 -1.0000E+001
...
        29         0         0        11  1.0000E+001  2.0000E+001  1.0000E+001
        30         0         0        11  5.0000E+000  5.0000E+000  5.0000E+000
    -1

ファイル2

    -1
    780
         1       116         1         2         1         1         7        20
         1        11         2        15         4        18         3        12
        13        16        22        19         5        24         9        29
         8        27         6        23
    -1

助けてくれてありがとう。

ベストアンサー1

-z(非標準 GNU 拡張)、NUL で区切られたレコードで動作しますが、そうではgrepありません。複数行 grep、だから:

  • 一致は、NULで区切られた各レコードに対して独立して実行されるか、区切りがない場合は完全な入力で実行されます(未区分のレコードを使用する機能は別のGNU拡張です)。
  • -o別の非標準GNU拡張)各一致に対してNULで区切られた出力

したがって、出力の記録ははい別途(実際には分離)。sed -n lたとえば、出力を渡すと、次のようになります。

$ grep -Pzo '(?s)((?m:^)\s{4}-1(?m:$).*?(?m:^)\s{4}-1(?m:$))' example.txt | sed -n l
    -1$
    15$
         1         0         0        11 -1.0000E+001  1.0000E+001 -1\
.0000E+001$
         2         0         0        11  1.0000E+001  1.0000E+001 -1\
.0000E+001$
...$
        29         0         0        11  1.0000E+001  2.0000E+001  1\
.0000E+001$
        30         0         0        11  5.0000E+000  5.0000E+000  5\
.0000E+000$
    -1\000    -1$
    780$
         1       116         1         2         1         1         \
7        20$
         1        11         2        15         4        18         \
3        12$
        13        16        22        19         5        24         \
9        29$
         8        27         6        23$
    -1\000$

\000各一致を区別するsを確認してください。

ここで一致を単純化できます。

grep -Pzo '(?sm)(^\s{4}-1$).*?(?1)' example.txt

grepただし、これを使用する代わりに-PPerlの非標準GNU拡張でもある)、実際に使用することができます。これにはいくつかの利点があります。

  • PerlはGNU grepよりも多くのシステムに存在するため、移植性が高くなります(Perlと同様の正規表現サポートがGNUビルドで常に有効になるわけではありませんgrep)。
  • Perlは-0NULで区切られたレコードを使用する必要がありますが、これはあなたが望むものではありません。あなたはフルルックを飲むモードが欲しいですperl-0777
  • Perlは独自に別々のファイルに出力を書き込むことができます。
perl -l -0777 -ne '
  while (/(^\s{4}-1$).*?(?1)/msg) {
    open OUT, ">", "output-" . ++$n . ".txt" or die;
    print OUT $&
  }' example.txt

または、ファイル全体を完全にインポートし、正規表現を使用する代わりに1行ずつ読みます。

perl -ne '
  if (/^\s{4}-1$/) {
    if ($inside = 1 - $inside) {
      open OUT, ">", "output-" . ++$n . ".txt" or die;
    } else {
      print OUT; next
    }
  }
  print OUT if $inside' example.txt

(すべて一致しなくても別の結果が表示されます-1)。


1これについては、GNUがオプションとして使用する(利用可能な)PCRE2に付属のサンプルアプリケーションpcre2grep -M(以前のpcregrep -M)を参照してください。pcre2grepgrep-P

おすすめ記事