最近我需要删除很多重复项。我正在合并三四个文件系统,并且希望经济地使用空间。起初,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
在自动删除重复项时保留(d
和N
一起切换)并且下面没有单独的文件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):看一下-X
2020 年添加的扩展过滤器选项。这并不完全是您想要的,但nostr
和onlystr
过滤器允许您指定完整路径中要忽略或需要的子字符串。
答案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`