再帰的に所定の位置合わせと重複排除

再帰的に所定の位置合わせと重複排除

すべてのサブディレクトリのすべてのファイルをソートしたいと思います。 256個のディレクトリに65536個のファイルがあり、各ファイルには1行に1語が含まれ、各ファイルには重複エントリが含まれています。

私が望むのは、-uオプションを使用してこれらの項目をソートすることです(理由はわかりませんが、ソートをuniq -uコマンドに渡すと、実際に重複した一意の行が削除されるのに奇妙ですが、とにかく)。これにより、どの出力ファイルも望ましくありません。メモリ内のファイルを並べ替えて読み込み、上書きしたいと思います。 -o オプションを試しましたが、ファイル名が必要です。

これを再帰的に実行する方法はありますか?

ありがとうございます:)

答え1

それは次のようになります:

find . -type f -size +1c -exec sort -uo {} {} ';'

(2バイト未満のファイルはここからスキップされます。2つの別々の行を作成するには、少なくとも3バイトが必要な場合、または空白行と無制限の行1が続く"\nx"2バイトが必要になる可能性があるため)。

デフォルトのソート順序は、sortロケールのデータソートアルゴリズムに基づいています。

2行は、バイト単位が同じでなくても同じように並べ替えることができます。特に、行に有効な文字を形成しないバイトシーケンスが含まれており、GNUシステム(Debianなど)では、ソート順序が同じでない場合はさらにそうです。文字に対しても同じように定義されているようにソートされます。

あなたはできます:

LC_ALL=C find . -type f -exec sort -uo {} {} ';'

対照的に、ASCIIベースのシステム(たとえば、すべてのアーキテクチャとカーネルのDebian)では、Cロケールの照合はロケールソート順序ではなくバイト値に基づいています(またはIOW、Cロケールの照合はバイト値に基づいています) 。 )行は並べ替えられ、バイトが異なる2つの行が等しく並べられないようにする必要があります。

sortこれはファイルごとに1つの呼び出しを実行します。ファイルが非常に短い場合は、作業を高速化するために次のことを行うことができますzsh

zmodload zsh/mapfile
for f (**/*(N.)) print -rC1 -v 'mapfile[$f]' - ${(fou)mapfile[$file]}

sortこれにより、外部コマンドが複数回実行されるのを防ぎ、代わりにoパラメータu拡張フラグを使用して行を並べ替えて一意に並べ替えます。入力から空白行(存在する場合)を削除し、隠しファイルをスキップします(D必要に応じてglob修飾子を追加します)。

GNUとは異なり、sort -uバイトzsh単位で等しくない2つの文字列は重複と見なされないため(同じ順序であっても)ロケールをCに変更する必要はありません。

$ロケールヘッダー文字マップ
英国式英語環境
UTF-8
$a=(

答え2

$ find . -type f -exec perl -MList::MoreUtils=uniq -i -0 -n -e \
    'print join("\n", uniq split /\n/), "\n"' {} +

これは、内部編集オプションを使用してfindファイル名をスクリプトに渡すために使用されます。perl-iリスト::追加ユーティリティuniqPerlに機能を提供します(Perlにはsort組み込み機能がありますが、1つはありませんuniq)。 perlのオプションは-n各入力レコードを繰り返しますが、デフォルトでは何も印刷しません(つまり、明示的に印刷された内容のみを印刷します)。sed-n

スクリプトは、-0各ファイルを一度に飲み込むことができるように、入力レコード区切り文字を対応するオプションを使用してNULに設定します。次に、各入力ファイルを改行文字に分割し、一意のソート順で印刷します。

List::MoreUtilsDebian(およびUbuntu、Mintなど)のパッケージにあり、liblist-moreutils-perlFedora、Centos、またはRHELにも同様のパッケージ名があります。他のディストリビューションでもそれをパッケージ化できます。それ以外の場合は、CPANからインストールしてください。

をインストールしたくない場合やインストールできない場合は、List::MoreUtils連想配列(「ハッシュ」とも呼ばれる)を使用できます。例えば

$ find . -type f -exec perl -i -0 -n -e \
    '%uniq = map {$_ => 1} split /\n/;
     print join("\n", sort keys %uniq), "\n"' {} +

まず、いくつかのジャンクファイルでこれらのいずれかを実行して、必要に応じて動作することを確認します。および/または-i標準出力として印刷するオプションなしでテストします。junk次の内容を含むファイルでテストしました。

6
5
5
4
3
2
1
1

上記のバージョンのいずれかを実行した後、次のものがjunk含まれます。

1
2
3
4
5
6

逆順にするには、reverseまたは関数の前に追加するだけです。例えば。sortuniqprint join("\n", reverse sort keys %uniq),"\n"


またはあなたが持っているならスポンジJoey Hessのインストールでは、および以下をmoreutils使用できます。findshellsort -usponge

find . -type f -exec sh -c \
  'for f in "$@"; do sort -u "$f" | sponge "$f" ; done' find-sh {} +

これは一度shフォークする必要があるため、Perlバージョンよりはるかに遅いです。sortspongeそれぞれすべての入力ファイルを処理するperlために一度(*)だけ分岐するのではなく、入力ファイルを処理します。find

(*) すべてのファイル名がコマンドラインに適合すると仮定します。 Linuxでは、約200万文字に相当します。結合されたすべてのファイル名がこれより長い場合は、Perlを2〜3回(またはそれ以上)分岐する必要があります。

sh複数回フォークする必要があるフォークにも同じことが当てはまります。ただし、findsh(またはperl)を数回フォークするコストは、合計をフォークするコストと比較して無視できます。sortsponge ファイルごとに1回。代わりに+withを使用すると時間が節約されます。find ... -exec ... {}\;

関連情報