有条件删除重复文件

有条件删除重复文件

我只想在文件共享相同名称的情况下删除重复项。
比如:rdfind -deleteduplicates true ~/folder不会实现我的目标。

一种想法可能是获取试运行的 rdfind 的输出(results.txt),

rdfind -n true "$PWD"

并确定哪些文件与每组中的第一个文件具有相同的名称,以以下开头标识:DUPTYPE_FIRST_OCCURRENCE XXXX

DUPTYPE_FIRST_OCCURRENCE 5148 2 37934240 2054 16916792 1 /home/fig3.tif
DUPTYPE_WITHIN_SAME_TREE -5148 3 37934240 2054 17044654 1 /home/other/fig3.tif
DUPTYPE_WITHIN_SAME_TREE -5148 3 35435435 2054 16546546 1 /home/other2/fig3.tif

DUPTYPE_FIRST_OCCURRENCE 5160 2 116397930 2054 16916804 1 /home/file.psd
DUPTYPE_WITHIN_SAME_TREE -5160 2 116397930 2054 16916870 1 /home/folder/file.psd
DUPTYPE_WITHIN_SAME_TREE -5160 2 116397930 2054 17654654 1 /home/folder/file2.psd

在上面的示例中,对于第一组,应删除 2 个重复项,而在第二组中,仅应删除一个重复项,该重复项与第一个出现项 (file.psd) 具有相同的名称。

编辑:rmlint 的答案将是可取的。通常可以使用以下命令建立“原始”文件林特

答案1

results.txt该脚本将对生成的文件进行后处理,rdfind如您的问题所示:

#!/bin/bash
#
while read -r type x x x x x x path
do
    case "$type" in

        DUPTYPE_FIRST_OCCURRENCE)
            name="${path##*/}"
            echo "New path for $name" >&2
            ;;

        DUPTYPE_WITHIN_SAME_TREE|DUPTYPE_OUTSIDE_TREE)
            if [[ -n "$name" ]] && [[ ${path##*/} == $name ]]
            then
                echo "Remove duplicate $path" >&2
                # rm -f "$path"
            else
                echo "Skipping differently named $path" >&2
            fi
            ;;
    esac
done

rm当您准备好让它完成工作时,请取消注释。注释掉echo语句(或重定向标准错误)如果你不想冗长。

read -r type x x x x x x path循环顶部的语句读取八个空格分隔的字段。中间的六个不相关,因此我将它们读入垃圾变量,然后将其丢弃;仅$type$path被使用。

产生results.txt

rdfind -dryrun true -makeresultsfile true {directory...}

后处理生成的文件(rddedup是我的脚本,如上所示)

rddedup < results.txt

答案2

如何用另一种方式给这只猫剥皮? (OP编辑请求rmlint是在我正要发布此内容时发出的,但没关系,也可以发布此内容......请参阅底部的编辑rmlint

由于结构已知,文件名的第一次出现是目标,并且在删除空行之前的后续重复文件名,那么我们也可以享受乐趣,awk尽管可能比 @roaima 慢一些

awk 'NF==0{getline; target=""}
     target==""{l=split($8,t,"/"); target=t[l];getline}
     {l=split($8,q,"/");if (q[l]==target)print $8}' file1 | while read f; do echo rm $f ; done

演练

如果我们有空行,请跳过它并将目标文件名重置为""

awk 'NF==0{getline; target=""}

如果目标未设置(即在每个空行之后和开始处),那么我们从此行获取目标文件名并跳到下一行

     target==""{l=split($8,t,"/"); target=t[l];getline}

现在对照目标检查当前行中的文件名,如果匹配则输出完整路径

     {l=split($8,q,"/");if (q[l]==target)print $8}' file1

然后awk通过循环进行实际删除(仅删除echo)。

    | while read f; do echo rm $f ; done

虽然你也可以这样做(同样只需删除echo

     {l=split($8,q,"/");if (q[l]==target)print $8}' file1 | xargs echo rm

编辑rmlintfront 看来你无法轻易控制的优先级独创性

默认情况下,如果您在 rmlint 命令中指定多个路径,则第一个命名的路径中的文件将被视为比后面命名的路径更“原始”。如果同一路径中有两个文件,则较旧的文件将被视为原始文件。如果它们具有相同的修改时间,那么选择哪一个作为原始版本只是一个机会问题。

但对于您的明确示例,该-d选项(原始是文件层次结构中的最低层)将与 结合使用,-b以按文件名而不是内容进行匹配。

rmlint -d -b /home/

诚然,这是一个很多比我的脚本短,但阅读rmlint页面比编写脚本花费的时间更长。随你挑选。

未经测试,顺便说一下......

答案3

这是 roaima 的脚本,针对重复项相互对应但它们不是给定文件列表中的第一个的情况进行了纠正。例如。同一个文件有三个名称:a/xb/yc/y.那么当a/x基本文件( DUPTYPE_FIRST_OCCURRENCE) 时,其他文件之一将被删除。

#!/bin/bash

while read -r type x x x x x x path
do
    name="${path##*/}"
    [[ "$type" == '#' ]] || [[ -z "$name" ]] && 
        printf "%s\n" "skipping a non-entry looking line">&2
    case "$type" in
        DUPTYPE_FIRST_OCCURRENCE)
            printf "New path for %s: %s\n" "$name" "$path">&2
            unset ass
            declare -A ass
            ass["$name"]=1
            ;;

        DUPTYPE_WITHIN_SAME_TREE|DUPTYPE_OUTSIDE_TREE)
            if [ "${ass["$name"]}"x != "x" ]
            then
                printf "Remove duplicate: %s\n" "$path" >&2
                # rm -f "$path"
            else
                ass["$name"]=1
                printf "Skipping differently named file: %s\n" "$path" >&2
            fi
            ;;
    esac 
done < results.txt

其中还包括一些其他更改,无需注释即可阅读。ass是一个关联数组。

我必须承认这个脚本还没有经过充分的测试,因此可能仍然存在一些未解决的极端情况。

用法示例。 rdfind -n true .然后我们有这个:

$ ls *
results.txt  script.bash

a:
filea0  filea1  fileb0

b:
filea1  fileb0

c:
fileb0

结果.txt:

$ cat results.txt 
# Automatically generated
# duptype id depth size device inode priority name
DUPTYPE_FIRST_OCCURRENCE 4 1 6 64773 4849814 3 ./a/filea0
DUPTYPE_WITHIN_SAME_TREE -4 1 6 64773 4849816 3 ./b/filea1
DUPTYPE_WITHIN_SAME_TREE -4 1 6 64773 4849817 3 ./a/filea1
DUPTYPE_FIRST_OCCURRENCE 6 1 6 64773 4849677 3 ./a/fileb0
DUPTYPE_WITHIN_SAME_TREE -6 1 6 64773 4849819 3 ./b/fileb0
DUPTYPE_WITHIN_SAME_TREE -6 1 6 64773 4986586 3 ./c/fileb0
# end of file

正在运行的脚本:

./script.bash
skipping a non-entry looking line
skipping a non-entry looking line
New path for filea0: ./a/filea0
Skipping differently named file: %s\n ./b/filea1
Remove duplicate: ./a/filea1
New path for fileb0: ./a/fileb0
Remove duplicate: ./b/fileb0
Remove duplicate: ./c/fileb0
skipping a non-entry looking line

相关内容