web-dev-qa-db-ja.com

マルチライン正規表現(grep、sed、awk、Perl)

複数行の正規表現が何十回も議論されていることは知っていますが、自分のパターンでそれを機能させることができません。

説明しようと思います。ディレクトリにいくつかのテキストファイルがあります。ファイル内のテキストの例:

LINE OF TEXT 2
LINE OF TEXT 1
LINE OF TEXT 3

LINE OF TEXT 1
LINE OF TEXT 2
LINE OF TEXT 3

LINE OF TEXT 1
LINE OF TEXT 3

LINE OF TEXT 3
LINE OF TEXT 2
LINE OF TEXT 1

LINE OF TEXT 2
LINE OF TEXT 3

「LINEOFTEXT1」の後に続く「LINEOFTEXT2」の後に続く「LINEOFTEXT3」を見つけたい(間に空行がない)。

各行はそれ自体が正規表現である必要があります。たとえば、行は「LINE」で始まり、特定の番号で終わります。

注:すべてのファイルにその正確な行シーケンスが含まれているわけではないため、パターンが一致する場合は、パターンを印刷せず、ファイル名をSTDOUTに出力するだけです。

これはワンライナー正規表現で実行できますか?したがって、たとえば、awkはファイル内のパターンを検索し、パターンが見つかった場合はファイル名をSTDOUTに出力します。次に、この正規表現を「find-exec」と組み合わせて使用​​できます。

言及されているツール(grep、awk、sed、Perl)はどれでも使用できます。

3
MikZyth

これをAwkで行うには、「Record Separator」変数を、少なくとも2つの連続する改行文字に一致する正規表現に設定します。

awk -v RS='\n\n+' '/1.*2.*3/' file.txt

「フィールド区切り文字」を単一の改行文字に設定することもできます。

awk -v RS='\n\n+' -F '\n' '$1 == "LINE OF TEXT 1" && $2 == "LINE OF TEXT 2" && $3 == "LINE OF TEXT 3"' file.txt

読みやすさのために分割:

awk -v RS='\n\n+' -F '\n' '
  $1 == "LINE OF TEXT 1" &&
  $2 == "LINE OF TEXT 2" &&
  $3 == "LINE OF TEXT 3"
' file.txt

一致するものが見つかった場合にのみファイル名を印刷するという要件がある場合、次のように行うことができます。

awk -v RS='\n\n+' -F '\n' '
  $1 == "LINE OF TEXT 1" &&
  $2 == "LINE OF TEXT 2" &&
  $3 == "LINE OF TEXT 3" {
    match++
  }
  END {
    if (match) {
      print FILENAME
    }
' file.txt

ただし、 findawkと組み合わせて使用​​ について話していることを考えると、終了ステータスにはAwkを使用し、終了ステータスにはfindを使用することをお勧めします。印刷:

find . -type f -exec awk -v RS='\n\n+' -F '\n' '
  $1 ~ /LINE OF TEXT 1/ &&
  $2 ~ /LINE OF TEXT 2/ &&
  $3 ~ /LINE OF TEXT 3/ {
    exit 0
  }
  END { exit 1 }
' {} \; -print

そうすれば、印刷する前に何かelseを実行したい場合(他のfindプライマリ)、実行するように設定されています。そう。

1
Wildcard

Perlで「段落モード」を使用できます。複数の改行で区切られたブロックでファイルが読み取られます。空の文字列を入力レコード区切り文字に設定するだけです$/

Perl -lne 'BEGIN { $/ = "" }
       $found = 1 if /^LINE.* 1\nLINE.* 2\nLINE.* 3$/m;
       if (eof) { print $ARGV if $found; undef $found }
' -- file1 file2...
  • eofは各ファイルの終わりでtrueです
  • $ARGVは、現在開いているファイルの名前です。
1
choroba

これは、次のように連携して動作するfind <-> Perlデュオを使用して実行できます。

find . -type f -exec \
  Perl -l -0777ne '/^LINE.* 1\nLINE.* 2\nLINE.* 3$/m && print $ARGV' {} +
0
Rakesh Sharma