如何查找和删除同一目录中的重复文件?

Su_*_*bee 7 duplicate find shell-script files

我想在一个目录中找到重复的文件,然后删除除一个之外的所有文件,以回收空间。如何使用 shell 脚本实现这一点?

例如:

pwd
folder
Run Code Online (Sandbox Code Playgroud)

里面的文件是:

log.bkp
log
extract.bkp
extract
Run Code Online (Sandbox Code Playgroud)

我需要将 log.bkp 与所有其他文件进行比较,如果发现重复文件(通过其内容),我需要将其删除。同样,文件“log”必须与所有其他文件一起检查,以此类推。

到目前为止,我已经写了这个,但它没有给出预期的结果。

#!/usr/bin/env ksh
count=`ls -ltrh /folder | grep '^-'|wc -l`
for i in `/folder/*`
do
   for (( j=i+1; j<=count; j++ ))
   do
      echo "Current two files are $i and $j"
      sdiff -s $i  $j
      if [ `echo $?` -eq  0 ]
      then
         echo "Contents of $i and $j are same"
       fi
    done
 done
Run Code Online (Sandbox Code Playgroud)

ein*_*onm 12

如果您乐于简单地使用命令行工具,而不必创建 shell 脚本,那么fdupes大多数发行版都可以使用该程序来执行此操作。

还有fslint具有相同功能的基于 GUI 的工具。

  • @Su_scriptingbee 如果您让我们知道您的系统是什么,则可能会建议安装它的方法。 (2认同)

roa*_*ima 9

此解决方案将在 O(n) 时间内找到重复项。每个文件都有一个为它生成的校验和,每个文件依次通过关联数组与一组已知的校验和进行比较。

#!/bin/bash
#
# Usage:  ./delete-duplicates.sh  [<files...>]
#
declare -A filecksums

# No args, use files in current directory
test 0 -eq $# && set -- *

for file in "$@"
do
    # Files only (also no symlinks)
    [[ -f "$file" ]] && [[ ! -h "$file" ]] || continue

    # Generate the checksum
    cksum=$(cksum <"$file" | tr ' ' _)

    # Have we already got this one?
    if [[ -n "${filecksums[$cksum]}" ]] && [[ "${filecksums[$cksum]}" != "$file" ]]
    then
        echo "Found '$file' is a duplicate of '${filecksums[$cksum]}'" >&2
        echo rm -f "$file"
    else
        filecksums[$cksum]="$file"
    fi
done
Run Code Online (Sandbox Code Playgroud)

如果您没有在命令行上指定任何文件(或通配符),它将使用当前目录中的文件集。它将比较多个目录中的文件,但不会写入目录本身。

该集中的“第一个”文件始终被视为最终版本。不考虑文件时间、权限或所有权。只考虑内容。

当您确定它可以满足您的要求时,将其echorm -f "$file"行中删除。请注意,如果您要替换该行,ln -f "${filecksums[$cksum]}" "$file"您可以硬链接内容。同样节省磁盘空间,但不会丢失文件名。


ilk*_*chu 2

脚本中的主要问题似乎是i将实际文件名作为值,而j只是一个数字。将名称放入数组并使用ij作为索引应该可以工作:

files=(*)
count=${#files[@]}
for (( i=0 ; i < count ;i++ )); do 
    for (( j=i+1 ; j < count ; j++ )); do
        if diff -q "${files[i]}" "${files[j]}"  >/dev/null ; then
            echo "${files[i]} and ${files[j]} are the same"
        fi
    done
done
Run Code Online (Sandbox Code Playgroud)

(似乎可以与 Bash 和ksh/ ksh93Debian 一起使用。)

该赋值操作将使用两个元素和(索引为 0 和 1)a=(this that)来初始化数组。分词和通配符照常工作,因此使用当前目录中所有文件的名称(点文件除外)进行初始化。将扩展到数组的所有元素,哈希符号要求长度,数组中元素的数量也是如此。(请注意,这将是数组的第一个元素,并且是第一个元素的长度,而不是数组!)athisthatfiles=(*)files"${files[@]}"${#files[@]}${files}${#files}

for i in `/folder/*`
Run Code Online (Sandbox Code Playgroud)

这里的反引号肯定是一个错字吗?您将作为命令运行第一个文件,并将其余文件作为参数提供给它。