【问题标题】:How to find files with same size?如何找到相同大小的文件?
【发布时间】:2011-09-24 20:12:30
【问题描述】:

我有这样的文件结构

a/file1
a/file2
a/file3
a/...
b/file1
b/file2
b/file3
b/...
...

在每个目录中,有些文件的文件大小相同,我想删除这些文件。

我猜这个问题是否可以通过一个目录来解决,例如dir a,那么我可以在它周围包裹一个for循环吗?

for f in *; do
???
done

但是如何找到大小相同的文件呢?

【问题讨论】:

  • 它们是相同尺寸还是相同尺寸?

标签: linux bash awk


【解决方案1】:
 ls -l|grep '^-'|awk '{if(a[$5]){ a[$5]=a[$5]"\n"$NF; b[$5]++;} else a[$5]=$NF} END{for(x in b)print a[x];}'

这只会检查文件,不会检查目录。

$5 是 ls 命令的大小

测试:

kent@ArchT60:/tmp/t$ ls -l
total 16
-rw-r--r-- 1 kent kent  51 Sep 24 22:23 a
-rw-r--r-- 1 kent kent 153 Sep 24 22:24 all
-rw-r--r-- 1 kent kent  51 Sep 24 22:23 b
-rw-r--r-- 1 kent kent  51 Sep 24 22:23 c
kent@ArchT60:/tmp/t$ ls -l|grep '^-'|awk '{if(a[$5]){ a[$5]=a[$5]"\n"$NF; b[$5]++;} else a[$5]=$NF} END{for(x in b)print a[x];}'
a
b
c
kent@ArchT60:/tmp/t$ 

根据 Michał Šrajer 的评论更新

现在也支持带空格的文件名

命令:

 ls -l|grep '^-'|awk '{ f=""; if(NF>9)for(i=9;i<=NF;i++)f=f?f" "$i:$i; else f=$9; 
        if(a[$5]){ a[$5]=a[$5]"\n"f; b[$5]++;} else a[$5]=f}END{for(x in b)print a[x];}'

测试:

kent@ArchT60:/tmp/t$ l
total 24
-rw-r--r-- 1 kent kent  51 Sep 24 22:23 a
-rw-r--r-- 1 kent kent 153 Sep 24 22:24 all
-rw-r--r-- 1 kent kent  51 Sep 24 22:23 b
-rw-r--r-- 1 kent kent  51 Sep 24 22:23 c
-rw-r--r-- 1 kent kent  51 Sep 24 22:40 x y

kent@ArchT60:/tmp/t$ ls -l|grep '^-'|awk '{ f=""
        if(NF>9)for(i=9;i<=NF;i++)f=f?f" "$i:$i; else f=$9; 
        if(a[$5]){ a[$5]=a[$5]"\n"f; b[$5]++;} else a[$5]=f} END{for(x in b)print a[x];}'
a
b
c
x y

kent@ArchT60:/tmp/t$

【讨论】:

  • 很好的解决方案 (+1)。对于不熟悉 awk 的人,$NF 是最后一个字段(文件名)。一,备注 - 此解决方案不适用于包含空格的文件名。
  • 很酷的解决方案! =) 如果我执行for f in $(find . -type d);do cd "$f" &amp;&amp; your_solution &amp;&amp; cd ..;done,那么cd 命令将失败。你将如何在每个目录中执行你的脚本?
  • @MichałŠrajer 非常感谢您指出这一点。我已根据您的评论更新了我的答案。但是,如果文件名有连续的空格,例如"foo bar" awk 行将失败。 ^_^
  • @SandraSchlichting 举个例子,假设您在“/tmp”下运行 for 脚本。您的 find . -type d 将在 /tmp 下找到所有目录(以及子目录)。假设在 /tmp 下,我们有 /tmp/a、/tmp/a/a2/a3、/tmp/b。您的“查找”输出将是 ./a、./a/a2/a3 和 ./b。所以如果你 cd ./a/a2/a3 并做了什么,那么cd .. 会带你到/tmp/a/a2,接下来你想做 cd "./b",很明显,没有"b" /tmp/a/a2 下的目录。所以你明白了。该错误与awk无关。你必须完善你的寻找脚本。
  • @Kent:我明白了。我当然应该使用-maxdepth 1for f in $(find . -maxdepth 1 -type d);do cd "$f" &amp;&amp; your_solution;done。没有错误,但也没有输出。我怀疑 cd "$f= 并没有真正的 cd。
【解决方案2】:

使用“带空格的文件名”的解决方案(基于 Kent (+1) 和 awiebe (+1) 帖子):

for FILE in *; do stat -c"%s/%n" "$FILE"; done | awk -F/ '{if ($1 in a)print $2; else a[$1]=1}' | xargs echo rm

要使其删除重复项,请从 xargs 中删除 echo

【讨论】:

  • 如果我想在无限数量的子目录中递归查找文件,我该如何修改?那真的很有帮助。
【解决方案3】:

如果您需要文件的大小,这里是代码:

FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."

然后使用 for 循环获取结构中的第一项, 将该文件的大小存储在一个变量中。

在该 for 循环中将 for 循环嵌套到结构中的每个项目(不包括当前项目)到当前项目。

将相同文件的所有名称路由到一个文本文件中,以确保您已正确编写脚本(而不是立即执行 rm)。

对该文件的内容执行 rm。

【讨论】:

    【解决方案4】:

    根据接受的答案,以下提供了当前目录中所有相同大小的文件的列表(因此您可以选择保留哪个文件),按大小排序:

    for FILE in *; do stat -c"%s/%n" "$FILE"; done | awk -F/ '{if ($1 in a)print a[$1]"\n"$2; else a[$1]=$2}' | sort -u | tr '\n' '\0' | xargs -0 ls -lS
    

    要确定文件是否实际上相同,而不仅仅是包含相同数量的字节,请对每个文件执行 shasummd5sum

    for FILE in *; do stat -c"%s/%n" "$FILE"; done | awk -F/ '{if ($1 in a)print a[$1]"\n"$2; else a[$1]=$2}' | sort -u | tr '\n' '\0' | xargs -0 -n1 shasum
    

    【讨论】:

      【解决方案5】:

      简单的 bash 解决方案

      find -not -empty -type f -printf "%s\n" | 
      sort -rn | uniq -d | 
      xargs -I{} -n1 find -type f -size {}c -print0 | 
      xargs -0 du | sort
      

      【讨论】:

        【解决方案6】:

        看起来你真正想要的是duplicate file finder

        【讨论】:

        • 有人会这么认为,但我发现 youtube-dl 创建的大型视频并不相同,但足够接近您想要删除其中一个的程度。
        【解决方案7】:

        听起来这个问题已经多次以不同的方式回答过,所以我可能是在打死马,但是这里……

        找到 DIR_TO_RUN_ON -size SIZE_OF_FILE_TO_MATCH -exec rm {} \;

        find 是一个很棒的命令,我强烈建议阅读它的手册页。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-02
          • 2014-03-22
          • 1970-01-01
          相关资源
          最近更新 更多