【问题标题】:Find files with same name but different content查找同名但内容不同的文件
【发布时间】:2015-07-20 18:03:23
【问题描述】:

我需要在一个文件很多的linux文件夹结构中找到同名但内容不同的文件。

这样的东西部分地完成了工作,我如何消除具有不同内容的文件?

#!/bin/sh 
dirname=/path/to/directory
find $dirname -type f | sed 's_.*/__' | sort|  uniq -d| 
while read fileName
do
find $dirname -type f | grep "$fileName"
done

(How to find duplicate filenames (recursively) in a given directory? BASH)

非常感谢!

【问题讨论】:

  • 如果你有 3 个文件都名为 spam.txt,并且它们都有不同的内容,你想删除哪 2 个?
  • 您是否正在寻找执行此操作的 python 代码?
  • 无论你想出什么规则,你显然需要一些代码来应用该规则......除非规则真的是“我不在乎,只要杀了他们两个,保留另一个”。在这种情况下,这很容易。你有一个重复文件的列表。您想删除任意选择的除一个以外的所有内容。所以只需从列表中弹出第一个,然后删除所有其余的。
  • 如果规则是“保留最旧的”,那么您需要首先按时间排序列表(如果您只是做了@ 987654324@ by -name 而不是 find 的所有内容,然后是 grep 的名称...),或者只是 stat 循环中的每个文件并从列表中删除最旧的文件。 (我认为这在 Python 中要比在 bash 中容易得多……)
  • 感谢您的快速cmets。 @abarnert,我只想列出它们并自己消除它们。埃里克什么都好。

标签: python linux sed


【解决方案1】:

第一个问题是,如何判断两个文件的内容是否相同?

一个明显的可能性是读取(或映射)两个文件并一次比较它们一个块。在某些平台上,statread 快很多,因此您可能需要先比较大小。还有其他可能有用的优化,这取决于您实际在做什么(例如,如果您要运行数千次,并且大多数文件每次都相同,您可以对它们进行哈希处理并缓存哈希值,并且仅在哈希值匹配时检查实际文件)。但是我怀疑如果您的现有代码是可以接受的(因为它会为树中的每个文件搜索整个树一次),那么您是否过于担心这种性能调整,所以让我们做最简单的事情。

这是在 Python 中执行此操作的一种方法:

#!/usr/bin/env python3
import sys

def readfile(path):
    with open(path, 'rb') as f:
        return f.read()

contents = [readfile(fname) for fname in sys.argv[1:]]
sys.exit(all(content == contents[0] for content in contents[1:]))

如果所有文件都相同,这将退出代码 1,如果任何一对文件不同,则代码 0。因此,将其保存为allequal.py,使其可执行,您的 bash 代码可以在该grep 的结果上运行allequal.py,并使用退出值(例如,通过$?)来决定是否打印这些结果给你。

【讨论】:

  • 在 python 中使用hashlib 不是比逐块比较文件更简单的方法吗?
  • @fixxxer:不是真的。如果您不关心阅读整个文件,f.read() 甚至比您可以使用hashlib 做的任何事情都简单。如果你想早点退出,逐块读取仍然比逐块散列更简单。我想在您不介意浪费时间阅读整个文件但介意浪费 RAM 的情况下,散列可能比映射更简单,但除此之外,什么时候会让事情变得更容易?
  • 如果你有一个文件列表,你想匹配一个新文件来测试重复,那么它可能有用吗?将一个文件与其他多个文件匹配会很浪费(不是 OP 要求的,而是一般要求的)
  • @fixxxer:当然,如果你想在每次有几个新文件时一遍又一遍地重复这项工作,而不必重新读取所有旧文件,那么哈希是一个很好的优化.但仍然不是更简单(特别是因为如果哈希匹配,您仍然需要读取文件以处理冲突);它更复杂,但为了提高效率可能值得。
  • @fixxxer:但是,再一次,任何真正关心效率的人都不会首先在他的树上编写二次搜索。事实上,现在我想起来了,我不应该一开始就包括逐块优化。让我重新编辑。
【解决方案2】:

我面临与问题中描述的相同的问题。在大型目录树中,一些文件具有相同的名称和相同的内容或不同的内容。内容不同的地方需要人工来决定如何解决每种情况下的情况。我需要创建这些文件的列表来指导执行此操作的人。

问题中的代码和 abernet 响应中的代码都有帮助。以下是如何将两者结合起来:将来自 abernet 响应的 python 代码存储在某个文件中,例如/usr/local/bin/do_these_files_have_different_content:

sudo tee /usr/local/bin/do_these_files_have_different_content <<EOF
#!/usr/bin/env python3
import sys

def readfile(path):
    with open(path, 'rb') as f:
        return f.read()

contents = [readfile(fname) for fname in sys.argv[1:]]
sys.exit(all(content == contents[0] for content in contents[1:]))
EOF

sudo chmod a+x /usr/local/bin/do_these_files_have_different_content

然后从 Illusionist 的问题中扩展 bash 代码,以便在需要时调用该程序,并对结果做出反应:

#!/bin/sh 
dirname=$1
find $dirname -type f | sed 's_.*/__' | sort|  uniq -d| 
while read fileName
do
if do_these_files_have_different_content $(find $dirname -type f | grep "$fileName")
then find $dirname -type f | grep "$fileName"
     echo
fi
done

这会将所有同名但内容不同的文件的路径写入标准输出。同名但内容不同的文件组用空行分隔。我将 shell 脚本存储在 /usr/local/bin/find_files_with_same_name_but_different_content 并调用它

find_files_with_same_name_but_different_content /path/to/my/storage/directory

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 2021-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多