重複したコンテンツを含むテキストファイルをお探しですか?

重複したコンテンツを含むテキストファイルをお探しですか?

何千ものファイルを処理するスクリプトの出力を上書きする(>)代わりに誤って追加(>>)しましたが、ファイルの約20%に対してのみこれを実行しました(スクリプトの並列インスタンスを5つ実行しました)。デフォルトでは、10行のテキスト、空白行、そして再び同じ10行のテキストがあります。

  1. このファイルをどうやって見つけることができますか?
  2. 2回目の繰り返しをどのように削除しますか?

1は2よりはるかに重要です。

何千ものファイルを処理するスクリプトの出力を上書きする(>)代わりに誤って追加(>>)しましたが、ファイルの約20%に対してのみこれを実行しました(スクリプトの並列インスタンスを5つ実行しました)。デフォルトでは、10行のテキスト、空白行、そして再び同じ10行のテキストがあります。

  1. このファイルをどうやって見つけることができますか?
  2. 2回目の繰り返しをどのように削除しますか?

1は2よりはるかに重要です。

(この質問は問題を示しています)


修正する:

内容を慎重に調べました。重複した内容を含むファイルの構造は次のとおりです。

<empty line>
<text>
<empty line>
<empty line>
<same text>
<empty line>

重複した内容がないファイルは

<empty line>
<text>
<empty line>

つまり、中央に2つの空行があるのです。最初の行の始点は上のテキストであり、2行目の始点は下のテキストです。テキストの上部と下部は空白行で囲まれています。

答え1

  1. 他の作業を実行する前に、現在のデータをバックアップしてください。問題が発生した場合は、いつでもこのコピーに戻すことができます。たとえば、次のものを使用できますtar

    tar cfz /path/to/backup-files.tar.gz /path/to/directory-to-backup/
    

    通常、次のようにする必要があります。いいえ関心のあるすべてのデータの一意のコピーを処理します。必ずバックアップをしておくか、コピーを作成して作業してください。つまり、あなたはしなければなりませんいつも変更を元に戻して間違いを取り消すための簡単で迅速な方法を自分に提供してください。

  2. \n「良い」ファイルに3回連続して改行文字()が表示されないと確信している場合は、次のことを試してください。コピーいくつかの「良い」ファイルと「悪い」ファイル:

    perl -i -0777 -p -e 's/\n{3,}.*/\n\n/' filenames
    

    これにより、3つの改行(テキスト行の末尾にある改行と2つの空行が続く)からファイルの終わりまでのすべての内容が削除され、2つの改行(1行はテキスト行の終わり)に置き換えられます。ファイルの末尾に追加したい空行)。

    すべてのファイルいいえ3つの連続した改行(つまり、回復する必要がない「良い」ファイル)があり、変更されません。

  3. Perlで処理したファイル(「良い」と「悪い」)を確認してください。

    予想と一致すると、ファイルを含むディレクトリ内のすべてのファイルに対してPerlスクリプトを実行します。たとえば、findすべてのファイルに.txt拡張子がある場合:

    find /path/to/directory -type f -name '*.txt' -exec \
      perl -i -0777 -p -e 's/\n{3,}.*/\n\n/' {} +
    

    find実際のディレクトリとファイル名に合わせてコマンドを調整してください)

答え2

ファイルを検索するには、複数文字のRSおよびENDFILEにGNU awkを使用します。

$ awk -v RS='\n{2}' '$0==p{f=1} {p=$0} ENDFILE{print FILENAME, (f ? "dups" : "uniq"); p=f=""}' file1 file2
file1 dups
file2 uniq

上記はこの入力で実行されます。

$ head file{1,2}
==> file1 <==

<text>


<text>


==> file2 <==

<text>

答え3

そしてperl

find . -type f -size +1c -exec perl -l -0777 -e '
  while (<<>>) {
    $size = length; $half = $size / 2;
    if ($size % 2 == 0 && substr($_, 0, $half) eq substr($_, $half)) {
      print "$ARGV is one of them";
      truncate $ARGV, $half or warn "truncate $ARGV: $!";
    }
  }' {} +

答え4

では、連想配列をzsh使用してファイルパスをその内容にマップできます。$mapfileこれにより、最初の半分と2番目の半分を簡単に比較し、その場所でファイルを更新できます。

#! /bin/zsh -
zmodload zsh/mapfile || exit
set +o multibyte

for file in **/*(ND.L+1); do
  text=$mapfile[$file]
  size=$#text
  if (( size % 2 == 0 )); then # even size
    (( half = size / 2 ))
    if [[ $text[1,half] = $text[half+1,-1] ]]; then
      print -r -- $file is one of them
      mapfile[$file]=$text[1,half] # or truncate -s$half -- $file
    fi
  fi
done

(検証されていません)。

**/*(ND.L+0)代わりに、**/*(ND.L+0m-1)過去24時間(または過去3時間など)**/*(ND.mh-3)で最後に変更されたファイルのみを処理できます。D隠しファイルが問題にならない場合は、削除してください。削除またはコメントアウトされ、mapfile[$file]=...一致するファイルのみを変更せずに一覧表示されます。

関連情報