递归查找文件,但从具有重复名称的文件中选择最大的文件

递归查找文件,但从具有重复名称的文件中选择最大的文件

给定一个包含各种文件的嵌套目录结构,我想找到其中的所有文件,但是如果有多个同名文件,我想只返回最大的文件。

因此,例如,给定一个如下的目录结构:

|--- 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也支持它。
  • **/*: 递归通配符。由 zsh 在九十年代初引入,现在在其他一些 shell 中也发现了它的变化。
  • (D.oL): 通配限定符。另一项 zsh 发明,尚未被其他 shell 复制,尽管它是递归通配符的重要伴侣。用于进一步限定 glob。D包含点文件,.仅包含常规的文件,oL按长度排序(大小以字节为单位)。
  • ${file:t}:就像 (t)csh 中一样,扩展到尾巴文件名的一部分(基本名称)。
  • ${a:|b}a扩展到中不存在的元素b。 (a-b)。

相关内容