ファイルから特定のパターンに一致するテキストを削除する方法

ファイルから特定のパターンに一致するテキストを削除する方法

2つのファイル(fileAとfileB)の違いを確認するために比較したいと思います。 fileAはテンプレートファイルと同じで、fileBは比較したいファイルです。違いを見つけるたびに、その違いをfileCに出力したいと思います。

難しいのは、fileAとfileBには、一部のデータ(時間、日付、およびランダムに生成されたIDコード)が常に他の一部(すべてではない)行が含まれていることです。しかし、唯一の違いは、時間、日付、およびIDコードだけのfileCに行を出力したくないことです。

だから私が望むのは、fileBに表示されるすべての行から時間、日付、およびIDコードを削除してから(fileAで手動でこれを実行できます)、fileBと比較して別の行をfileCに出力することです。

削除するテキストは常に特定のパターンに従うことに注意してください。だからgrepとこれらのパターンを使用してテキストを見つけることができますが、削除する方法がわかりません...

以下は、私が意味するものを説明する2つのファイルの例です。

  • 文書B

    qaqa rara
    abc 10:12:25 08/20/2014 123456 def
    ghi fff ddd
    jkl 09:20:40 08/20/2014 978645 dfdf gggg
    
  • ファイルA

    qaqa rara
    abc 10:32:15 07/15/2014 121456 xxx
    ghi eee ddd
    jkl 10:01:22 07/15/2014 971645 dfdf gggg
    

時間(例:10:12:25)、日付(例:08/20/2014)、またはIDコード(例:123456)を無視して、上の2つのファイルの違いを見つけて、違いをfileCに出力したいと思います。

2行が異なるため、2行と3行になります。両方のファイルの行1は同じです。時刻、日付、ID情報を削除すると、2つのファイルの4行目は同じです。

答え1

タイムスタンプが一貫した形式の場合は、diffメソッド(sedなど)を使用して、ファイルを処理する前にそれらを削除できます。

diff <(sed -E 's|[0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{2}/[0-9]{2}/[0-9]{2,4} [0-9]{1,} ||' fileA) <(sed -E 's|[0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{2}/[0-9]{2}/[0-9]{2,4} [0-9]{1,} ||' fileB)

指定した入力ファイルをテストします。

$ diff \
<(sed -E 's|[0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{2}/[0-9]{2}/[0-9]{2,4} [0-9]{1,} ||' fileA) \
<(sed -E 's|[0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{2}/[0-9]{2}/[0-9]{2,4} [0-9]{1,} ||' fileB)
2,3c2,3
< abc xxx
< ghi eee ddd
---
> abc def
> ghi fff ddd

答え2

結果を得る最も簡単なコマンドは次のとおりです。

$diff <(tr -s "[0-9],:,/" " " < ファイル A) <(tr -s "[0-9],:,/" " " < ファイル B)

コマンドは非常に単純で、複雑な正規表現はありません。

サンプル出力は次のとおりです。

2,3c2,3
< abc xxx
< ghi eee ddd
---
> abc def
> ghi fff ddd

これがあなたが望むものであることを願っています。

答え3

diff \
<(sed -r 's\[0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{2}/[0-9]{2}/[0-9]{4} [0-9]{6} \\' fileA) \
<(sed -r 's\[0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{2}/[0-9]{2}/[0-9]{4} [0-9]{6} \\' fileB) \
| egrep '^> ' | sed -r 's/^> //' > fileC

説明する

fileA と fileB から OP の質問に与えられた無関係な部分を削除し、diff に入力します。

diff は ">" の前に変更された部分を出力するので、変更を除くその他の内容はすべて無視されます。

最後に、出力から先行する">"を削除し、質問に従ってfileCに保存します。

最初は少し違ってしまいましたが、関係のない部分でファイルが異なる可能性があることがわかったので、ポストストリップではなくプリストリップを実行する必要があります。それ以外の場合は、関連部分のみがある場合、diffは実際には変更されていない情報を出力します。考慮。

与えられた入力例はcat fileC次のとおりです。

abc def
ghi fff ddd

sedコマンドは、無関係なデータを記述する提供された正規表現を検索し、それを空の文字列に置き換えます。つまり、削除します。

答え4

{   paste -d\| /dev/fd/3 /dev/fd/4 |
    sed '/\([^ ]*\) [0-9:/ ]*\(.*\)|\1 .*\2/d;=' |
    sed 'N;s/\(\n\)\(.*\)|/:\tFILEA: \2\1\tFILEB: /'
} 3<<\FILEA 4<<\FILEB
qaqa rara
abc 10:12:25 08/20/2014 123456 def
ghi fff ddd
jkl 09:20:40 08/20/2014 978645 dfdf gggg
FILEA
qaqa rara
abc 10:32:15 07/15/2014 121456 xxx
ghi eee ddd
jkl 10:01:22 07/15/2014 971645 dfdf gggg
FILEB

出力

2:      FILEA: abc 10:12:25 08/20/2014 123456 def
        FILEB: abc 10:32:15 07/15/2014 121456 xxx
3:      FILEA: ghi fff ddd
        FILEB: ghi eee ddd

時間と日付を削除する必要はありません。これを構成する文字が信頼できる限り大きな妨害にはなりません。

上記のパイプラインでは、pastefromの対応する行が最初にFILEB単一の区切り文字を使用して各行の末尾に追加され、次に結果が印刷されます。FILEA|stdout

sedストリームを選択して比較します。

  • 空白以外のゼロ文字以上の最初のシーケンス(として引用\1

  • 次のシーケンスの間に現れるすべての文字:(として引用\2

    • 1つ以上の<space>文字、次の文字のうち0つ以上:

    • <space>数値

    • <digit>数値

    • <:colon>数値

    • </slash>数値

  • |行に表示される最後の文字まで(含まない)

...そして|\1.*\2。一致する場合はsed行を削除します。それ以外の場合は、行番号の前に行がある行を印刷します。

最後sedのプロセスは、出力を美しくすることです。(私は希望)

関連情報