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 的工具。
此解决方案将在 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)
如果您没有在命令行上指定任何文件(或通配符),它将使用当前目录中的文件集。它将比较多个目录中的文件,但不会写入目录本身。
该集中的“第一个”文件始终被视为最终版本。不考虑文件时间、权限或所有权。只考虑内容。
当您确定它可以满足您的要求时,将其echo
从rm -f "$file"
行中删除。请注意,如果您要替换该行,ln -f "${filecksums[$cksum]}" "$file"
您可以硬链接内容。同样节省磁盘空间,但不会丢失文件名。
脚本中的主要问题似乎是i
将实际文件名作为值,而j
只是一个数字。将名称放入数组并使用i
和j
作为索引应该可以工作:
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
/ ksh93
Debian 一起使用。)
该赋值操作将使用两个元素和(索引为 0 和 1)a=(this that)
来初始化数组。分词和通配符照常工作,因此使用当前目录中所有文件的名称(点文件除外)进行初始化。将扩展到数组的所有元素,哈希符号要求长度,数组中元素的数量也是如此。(请注意,这将是数组的第一个元素,并且是第一个元素的长度,而不是数组!)a
this
that
files=(*)
files
"${files[@]}"
${#files[@]}
${files}
${#files}
for i in `/folder/*`
Run Code Online (Sandbox Code Playgroud)
这里的反引号肯定是一个错字吗?您将作为命令运行第一个文件,并将其余文件作为参数提供给它。