再帰的にファイルを検索しますが、重複する名前のファイルの中で最大のファイルを選択します。

再帰的にファイルを検索しますが、重複する名前のファイルの中で最大のファイルを選択します。

さまざまなファイルを含む入れ子になったディレクトリ構造が与えられたら、その中にあるすべてのファイルを探したいのですが、同じ名前のファイルが複数ある場合は、最大のファイルだけを返したいと思います。

たとえば、次のようなディレクトリ構造があるとします。

|--- foo.jpg (110 KB)
|--- bar.jpg (210 KB)
|--- dir
      |----- foo.jpg (860 KB)
      |----- baz.jpg (200 KB)

出力ラインを作成したいと思います(順序は重要ではありません)。

bar.jpg
dir/foo.jpg
dir/baz.jpg

可能な限りbashでこれを行うにはどうすればよいですか?

答え1

@UlrichSchwarzのコメントを具体化するために、次のように仕上げました。

find . -type f -printf "%s %P %f\n" | sort -k3,3 -k1,1rn | uniq -f 2 | cut -f 2 -d ' '

編集するたとえば、スペースを含むファイル名は処理されません。より強力なソリューションについては、@StéphaneChazelasのソリューションをご覧ください。

答え2

そしてzsh

typeset -A files
for f (**/*(D.oL)) files[$f:t]=$f
printf '%s\n' $files

ファイル名に含めることができる任意のバイトまたは文字(スペース、改行など)を使用できます。

GNUツールの使用:

find . -type f -printf '%s/%f/%P\0' |
  sort -zrn |
  LC_ALL=C sort -zt/ -uk2,2 |
  tr '\0\n' '\n\0' |
  cut -d/ -f3- |
  tr '\0' '\n'

重複を削除するには、以下を使用しますzsh

allfiles=(**/*(D.oL))
typeset -A best
for f ($allfiles) best[$f:t]=$f
bestfiles=($best)
dups=(${allfiles:|bestfiles})
rm -rf -- $dups

zshのいくつかの機能の説明:

  • typeset -A best:ksh93などの連想配列変数を宣言します。最新バージョンbashもサポートしています。
  • **/*:再帰的ワイルドカード。 90年代初頭にzshによって導入されたこのバージョンのバリエーションは、現在いくつかの他のシェルにあります。
  • (D.oL):ワイルドカード修飾子。再帰ワイルドカードの重要なコンパニオンですが、まだ他のシェルによってコピーされていない別のzsh発明です。地球をさらに限定するために使用されます。以下を含むDドットファイルが含まれています。.定期的なoL長さ(バイト単位)でソートされたファイル。
  • ${file:t}:(t)cshと同様に、次に展開されます。ファイル名(デフォルト名)の一部です。
  • ${a:|b}aに存在しない要素に展開されますb。 (ab)。

関連情報