有没有比 fdupes -rdN 更精细的删除重复项的方法?

有没有比 fdupes -rdN 更精细的删除重复项的方法?

最近我需要删除很多重复项。我正在合并三四个文件系统,并且希望经济地使用空间。起初,fdupes它似乎是完成这项工作的最佳工具,但我越来越遇到限制。

考虑命令fdupes -rdN somedirectory/。这会生成某个目录的子目录中所有文件的哈希值。

当它遇到重复项时,它会删除它们,以便所有内容都只有一份副本。

但是,如果我想保留somedirectory/subdirectory1/somefile并且实际上有四个重复项,并且程序首先遇到其中一个重复项,该怎么办?然后它删除了somedirectory/subdirectory1/somefile我不想要的。

我希望能够以某种方式指定要保留哪些重复项。到目前为止,处理重复项的标准程序(duff、FSLint)似乎都不允许这种行为的自动化。我不想自己动手,所以这就是我问这个问题的原因。

我希望能够写出类似的东西

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/

答案1

虽然您寻求的功能没有现货fdupes,但我分叉了fdupes (我的叉子叫jdupes并添加了一些功能,可以在某些情况下解决这个问题。例如,在上述情况下,您希望somedirectory/subdirectory1/somefile在自动删除重复项时保留(dN一起切换)并且下面没有单独的文件somedirectory,可以将第一个和切换(通过命令对文件进行排序)jdupes提供给每个直接子目录路径-行参数顺序优先):subdirectory1-O

jdupes -rdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

这将自动删除重复集中除一个文件之外的所有文件,并保证如果该集中包含一个文件,则该文件somedirectory/subdirectory1将是第一个文件,从而自动成为该集中保留的文件。这种方法仍然存在明显的限制,例如可能somedirectory/subdirectory1会保留另一个重复项,而不是您想要保留的重复项,但在很多像您这样的情况下,jdupes参数顺序选项作为一种解决方法就足够了。

在不久的将来,我计划添加一个过滤系统,该系统将能够对文件的包含/排除、操作的保存以及在全局或每个参数的基础上应用此类“过滤器堆栈”进行jdupes大量控制。-N这个功能是非常需要的;我设想这样的“自动递归删除非零重复项但始终保持somedirectory/subdirectory1/somefile原样”:

jdupes -rdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/

更新(2022-03-01):看一下-X2020 年添加的扩展过滤器选项。这并不完全是您想要的,但nostronlystr过滤器允许您指定完整路径中要忽略或需要的子字符串。

答案2

我在其他地方没有看到这个:说你想要的是这个。您有 /mnt/folder-tree-1 /mnt/folder-tree-2。您不想删除每个重复的文件,但如果树 2 中存在一个文件,并且树 1 中存在具有完全相同的路径和名称的相同文件,请将其从树 2 中删除。

警告:这非常简洁,如果您尝试使用有限的 shell 技能复制粘贴此内容,请小心。

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt

fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line
do
if grep -q "`echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|'`" dupes-all.txt
then
    echo rm \"$(echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2//|')\"
fi
done > rm-v2-dupes.sh

或者全部写在一行上:

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt; fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line; do if grep -q "`echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|'`" dupes-all.txt; then echo rm \"$(echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|')\"; fi; done > rm-v2-dupes.sh

然后,检查并执行 rm-v2-dupes.sh

答案3

将重复文件硬链接在一起怎么样?这样,该空间仅使用一次,但它们仍然存在于所有路径中。这样做的问题是硬链接文件应该就地修改(它们只能修改删除文件并使用新内容重新创建它)。另一种方法是将文件符号链接在一起,尽管您在决定哪个“主”文件是同样的问题。这可以通过以下脚本来完成(尽管请注意,这不处理包含空格的文件名)。

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
    for DEST in $DESTS; do
        ln -f $SOURCE $DEST
    done
done

答案4

只是为了给之前的答案添加一个转折。我多次使用了以下代码,稍微修改了之前的答案,简单地| grep隔离了我要从中删除的文件夹。

`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`

同样,这将创建一个 sh 文件来删除列出的所有文件,没有注释行。当然,您仍然可以编辑该文件以注释掉要保留的特定行/文件。

对于大型目录的另一个提示是对 txt 文件运行 fdupes,然后尝试| grep| sed直到得到我想要的结果。

`fdupes -r -n -S /directory > duplicate-files.txt`
`cat duplicate-files.txt | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`

相关内容