下面的代码用来删除重复文件并仅保留一个拷贝:
[Bash shell] 纯文本查看 复制代码 #!/bin/bash
ls -lS | awk 'BEGIN {
getline;getline;
name1=$8; size=$5
} { name2 = $8;
if (size == $5) {
"md5sum "name1 | getline; csum1=$1;
"md5sum "name2 | getline; csum2=$1;
if ( csum1 == csum2 )
{ print name1; print name2 }
};
size=$5; name1=name2;
}' | sort -u > duplicate_files
lines=`cat duplicate_files | wc -l`
let lines--
head -n $lines duplicate_files > deldupfile.txt
echo Removing..and keep a copy
cat deldupfile.txt | xargs rm
echo Removed duplicates files successfully.
先在当前的目录下创建几个重复的文件:$ echo hello > dup.txt
cp dup.txt dup2.txt; cp dup.txt dup3.txt; cp dup.txt dup4.txt
$ ls
del2.sh deldupfile.txt deldup.sh del.sh dup2.txt dup3.txt dup4.txt duplicate_files dup.txt myfile.txt newfile.txt 上面的几个文件是重复文件,重复文件的一个特点是其 md5 值相等,因此可以利用该特性进行查找出所有重复的文件,在删除这些重复的文件时我们又希望能够保留一份拷贝,因此在运行上面的代码后可以看到:$ ./deldup.sh
Removing..and keep a copy
Removed duplicates files successfully.
$ ls
del2.sh deldupfile.txt deldup.sh del.sh duplicate_files dup.txt myfile.txt newfile.txt
在上面的脚本代码中,ls -lS 是按照文件的大小来排列文件。在 awk 的 BEGIN部分,使用 getline 过滤掉第一行的无用信息(total xxx),然后再次使用 getline 读入第一条真正的文件信息行。
被 getline 读入的行默认以空格作为分隔符,因此 $8 表示文件名,$5 表示的是文件大小。
当 BEGIN 部分处理完后,真正进入 awk 的循环处理部分,在这个区域内,从管道输送过来的命令输出流会依次被处理。这里,会首先比较文件的大小是否相等,如果相等,那么才进一步比较文件的 md5 值,获取文件的 md5 值的命令是 md5sum 。如果 md5 值相等,那么说民这两个文件是完全重复的文件,所以经过 print name1; print name2; 这两条语句后,这两个重复的文件名会被打印出来,接下来执行 size=$5; name1=name2; 这两条语句以进行下一条信息的比较。当所有的比较工作完毕后,输出缓冲区里的内容会被送过管道。但是需要注意的是,因为上面每次处理最后打印的内容,name2 是会重复多次的,因此需要用 sort 命令的 -u 选项进行过滤掉重复行。最后,所有重复的文件名都被写到 duplicate_files 文件中。
接着统计了 duplicate_files 文件中的行数,也就是统计共有多少个重复的文件。由于最后要保留一个拷贝副本,因此打算将最后一个拷贝副本留下,其余要删除的文件的文件名全部写到 deldupfile.txt 文件中。这些工作做完后,可以删除重复文件了。 |