Linux 如何仅删除某个目录下的复制文件(具有相同的cksum)

Linux 如何仅删除某个目录下的复制文件(具有相同的cksum),linux,bash,awk,sed,solaris,Linux,Bash,Awk,Sed,Solaris,我构建以下脚本是为了删除具有相同cksum(或内容)的文件 问题是脚本可以删除两次以下示例中的文件(输出) 我的目标是只删除复制文件而不是源文件 脚本输出: Starting: Same: /tmp/File_inventury.out /tmp/File_inventury.out.1 Remove: /tmp/File_inventury.out.1 Same: /tmp/File_inventury.out.1 /tmp/File_inventury.out Remov

我构建以下脚本是为了删除具有相同cksum(或内容)的文件

问题是脚本可以删除两次以下示例中的文件(输出)

我的目标是只删除复制文件而不是源文件

脚本输出:

  Starting:
  Same: /tmp/File_inventury.out /tmp/File_inventury.out.1
  Remove: /tmp/File_inventury.out.1
  Same: /tmp/File_inventury.out.1 /tmp/File_inventury.out
  Remove: /tmp/File_inventury.out
  Same: /tmp/File_inventury.out.2 /tmp/File_inventury.out.3
  Remove: /tmp/File_inventury.out.3
  Same: /tmp/File_inventury.out.3 /tmp/File_inventury.out.2
  Remove: /tmp/File_inventury.out.2
  Same: /tmp/File_inventury.out.4 /tmp/File_inventury.out
  Remove: /tmp/File_inventury.out
  Done.

我的剧本:

 #!/bin/bash
  DIR="/tmp"
 echo "Starting:"
  for file1 in ${DIR}/File_inventury.out*; do
    for file2 in ${DIR}/File_inventury.out*; do
            if [ $file1 != $file2 ]; then
                    diff "$file1" "$file2" 1>/dev/null
                    STAT=$?
                    if [ $STAT -eq 0 ]
                     then
                            echo "Same: $file1 $file2"
                            echo "Remove: $file2"
                            rm "$file1"
                            break
                    fi
            fi
    done
 done
 echo "Done."

在任何情况下,我都想要ear–关于如何删除具有相同内容或cksum的文件的其他选项(实际上只需要删除重复文件,而不需要删除主文件)


请告知我们如何在solaris操作系统下做到这一点(例如,选项-查找一个liner、awk、sed…等)

此版本应该更高效。我对匹配正确的行感到紧张,但它似乎指定默认情况下对全局进行排序

for i in *; do
    date -u +%Y-%m-%dT%TZ -r "$i";
done > .stat;         #store the last modification time in a sortable format
cksum * > .cksum;     #store the cksum, size, and filename
paste .stat .cksum |  #data for each file, 1 per row
    sort |            #sort by mtime so original comes first
    awk '{
        if($2 in f)
            system("rm -v " $4); #rm if we have seen an occurrence of this cksum
        else
            f[$2]++              #count the first occurrence
    }'
这应该在
O(n*log(n))
时间内运行,每个文件只读取一次

您可以将其放入shell脚本中,如下所示:

#!/bin/sh

for i in *; do
    date -u +%Y-%m-%dT%TZ -r "$i";
done > .stat;
cksum * > .cksum;
paste .stat .cksum | sort | awk '{if($2 in f) system("rm -v " $4); else f[$2]++}';
rm .stat .cksum;
exit 0;
或者作为一个班轮:

for i in *; do date -u +%Y-%m-%dT%TZ -r "$i"; done > .stat; cksum * > .cksum; paste .stat .cksum | sort | awk '{if($2 in f) system("rm -v " $4); else f[$2]++}'; rm .stat .cksum;

我使用数组作为索引映射。所以我认为这仅仅是O(n)

#/bin/bash
arr=()
dels=()
f为1美元;做

由于文件内容相同,请阅读ck x fn,如何查找源代码?按文件名还是修改日期?如果是这样的话,您只需要在决定删除哪一个之前对其进行比较。此外,您当前的方法效率似乎很低,尤其是当文件很大时:假设有
n
不同的文件,您的脚本将读取它们大约
2*n*n
次。我的solaris机器中没有fdupes命令!你可以。这将比破解您自己的版本更简单、更高效。抱歉,我不能,因为我们不允许在客户或机器上执行此操作,但无法理解我需要如何处理您的代码,我需要用awk做什么?等一下,不要用它。我的
sort
语法中有一个错误,但是我会将其显示为bash脚本。好的。。。我试图将自己限制在POSIX规格的实用程序中。如果我错过了什么,请告诉我。
#!/bin/bash

arr=()
dels=()
for f in $1; do
  read ck x fn <<< $(cksum $f)
  if [[ -z ${arr[$ck]} ]]; then 
    arr[$ck]=$fn
  else
    echo "Same: ${arr[$ck]} $fn"
    echo "Remove: $fn"
    rm $fn
  fi
done