Grepはファイルの単語の段落と一致します。

Grepはファイルの単語の段落と一致します。

段落で構成されたファイル()がありますmyfile。つまり、項目は空行で区切られます。に基づいてこれらの段落のいくつかを検索したいと思いますmatch

今ゲームが1つだけであれば、すべてが面白くてゲームになります。私はただこうしていますawk -v RS='' '/match/ {print}' myfileここ。問題は、何百もの一致が見つかり、fileそれを別のファイル()に収集したことですmatchfile。一致する行のみを検索する必要がある場合grep -f matchfile myfile

grep -f段落全体を検索するなどの操作を実行する方法はありますか?私の好みのUnixはそれをサポートしていませんgrep -p

答え1

段落を1行に置き換え、grep -f matchfile結果を使用して改行を復元できます。

sed '/^$/s/^/\x02/' myfile | tr \\n$'\002' $'\003'\\n \
| grep -f matchfile |  tr $'\003' \\n | head -n -1

head出力に続く空行が問題にならない場合は、省略できます。
したがって、...各空白行の先頭にsed追加し、すべての改行を改行に変換します(元の行がいくつかの低いASCII文字で区切られたフィールドである単一行に効果的にすべての段落を変換します。これはテキストファイルで発生しますしません)。 - この場合)一致する項目のみを選択してください。\x02tr\x03\x02\x03grep「ワイヤー」;最後に、2番目はtr改行を復元し、次のhead空白行を削除します(たとえば、他のツールを使用できますsed \$d)。
実際にどのように動作するかを理解する最も簡単な方法は、段階的に実行することです。最初のコマンドを実行してから、最初と2番目のコマンドなどを実行し、出力を見てください。説明が必要です1


tr1:マニュアルを読んで慣れたら…

答え2

さて、それほど早くあきらめないでくださいawk

awk 'NR == FNR {
          aMatch[NR]=$0
          n=FNR
          next;
    }
    {
          RS="\n( |\t)*\n"
          for(i=1; i<n+1; i++) {
             if($0 ~ aMatch[i]) {
               print
               printf "\n"
               break                   
             }                 
          }
    }' matchFile myFile | head -n-1

ただし、これをスクリプトに入れることもできます。

awk -f myscript.awk matchFile myFile | head -n-1

awk実行操作の説明を含むスクリプト形式のソリューション:

# This block's instructions will only be executed for the first file (containing the lines to be matched)
# NR = number of line read, and FNR = number of line read in current file   
# So the predicate NR == FNR is only true when reading the first file !
NR == FNR {
   aMatch[NR]=$0          # Store the line to match in an array
   n=FNR                  # Store the number of matches
   next;                  # Tells awk to skip further instructions (they are intended for the other file) and process the next record
}
# We are now processing the second file (containing the paragraphs)
{
   RS="\n( |\t)*\n"          # Set record separator to a blank line. Instead of a single line, a record is now the entire paragraph
   for(i=1; i<n+1; i++) {    # Loop on all possible matches
      if($0 ~ aMatch[i]) {   # If $0 (the whole record i.e. paragraph) matches a line we read in file 1 then
         print               # Print the record (i.e. current paragraph)
         printf "\n"         # Print a new line to separate them. However we will end up with a trailing newline, hence the pipe to head -n-1 to get rid of it.
         break               # We need to break out of the loop otherwise paragraphs with n matches will be printed n times
      }                      # End of loop on matches
   }                         # End of 2nd file processing
}

答え3

これを行うのはとても簡単です。

awk -v RS="" -v ORS="\n\n" '/match/' myfile

関連情報