shell脚本实现查找文件夹下重复的文件,并提供删除功能
Windows下有软件FindDupFile,可以搜索指定目录及其下子目录,列出所有内容完全相同的文件(文件名可能不同),然后由用户选择删除重复的文件。
然而shell脚本却可以使用几行的命令完成与此相同的工作,借助windows下的shell脚本工具Cygwin,可以实现扫描Windows下的目录,原理简述如下:
1.首先借助find命令扫描文件夹下类型为普通文件的所有文件,find命令的输出是一行一个文件
2.对find找到的所有文件进行MD5校验,校验命令为md5sum files,输出文本格式为:MD5SUM *file
3.内容的文件的md5校验值是相同的,所有对MD5SUM校验值进行相同值查询,因此使用awk的关联数组,将不相同的文件输出
4.对awk输出重复的文件表进行删除。
shell脚本如下:
#!/bin/bash -#查找文件夹下相同的文件
#Usage: dupfile.sh [-ds] dirs
# dirs 请用单引号引起来del=0
silent=0trap "" PIPE#参数处理
while test $# -gt 0
docase $1 in-d | --delete) del=1;;-s | --silent)silent=1;;-*) break;;*) break;;esacshift
doneif [ $# -eq 0 ]
thenecho "Usage: dupfile.sh [-ds] dirs" >&2exit 0
fi#find查找所有文件并进行MD5校验,
# md5sum对二进制文件输出为 MD5SUM *file
# awk使用关联数组处理相同的md5值并按照格式输出,使用DEL传递参数
# tee命令将管道拷贝一份到进程替换,另一份到stdout
find "$@" -type f -exec md5sum {} + | awk -v FS="*" -v DEL=$del -v SLT=$silent '{if($1 in md5)md5[$1] = md5[$1] "*" $2elsemd5[$1] = $2}END{for(key in md5){if(DEL==0) K++n = split(md5[key], files, "*")if(SLT==1 && n==1) continueif(DEL==0)printf("%-*s %s\n", length(key), key, files[n])for(n-- ;n>0 ; n--){K++if(DEL==0)printf("%-*s %s\n", length(key), "", files[n])elseprintf("\"%s\"\n", files[n]) }}K = K>0 ? K : 0print "Total: " K " files" }' |tee >(if [ "$del" -eq 1 ]thenxargs rm -felsetee >/dev/nullfi)
看看用Cygwin在Windows下的测试结果: (注意将列出的所有目录加单引号)
首先,我在E盘test目录下创建10个临时文件,文件都为空,测试结果如下:
hp@hp-PC ~
$ (cd 'E:/test'; i=0; while [ "$i" -lt 10 ] ; do mktemp "./XXXXXX" ; i=$((i+1)) ; done)
./pOsdFm
./5tndDZ
./wjSDR2
./oFrSaG
./7zlZcA
./9sNmEo
./UVDQLR
./qZdDNI
./iwfYdn
./IP52BKhp@hp-PC ~
$ ./dupfile.sh 'E:/test'
cygwin warning:MS-DOS style path detected: E:/testPreferred POSIX equivalent is: /cygdrive/e/testCYGWIN environment variable option "nodosfilewarning" turns off this warning.Consult the user's guide for more details about POSIX paths:http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
d41d8cd98f00b204e9800998ecf8427e E:/test/wjSDR2E:/test/UVDQLRE:/test/qZdDNIE:/test/pOsdFmE:/test/oFrSaGE:/test/iwfYdnE:/test/IP52BKE:/test/9sNmEoE:/test/7zlZcAE:/test/5tndDZ
Total: 10 fileshp@hp-PC ~
$
从结果中看出,已经完全的将10个重复的空文件完全查找出来。
使用-d选项,则可以删除重复的,只保留其中的一个。
hp@hp-PC ~
$ (cd 'E:/test' ; ls ;)
5tndDZ 7zlZcA 9sNmEo IP52BK iwfYdn oFrSaG pOsdFm qZdDNI UVDQLR wjSDR2hp@hp-PC ~
$ ./dupfile.sh -d 'E:/test'
"E:/test/UVDQLR"
"E:/test/qZdDNI"
"E:/test/pOsdFm"
"E:/test/oFrSaG"
"E:/test/iwfYdn"
"E:/test/IP52BK"
"E:/test/9sNmEo"
"E:/test/7zlZcA"
"E:/test/5tndDZ"
Total: 9 fileshp@hp-PC ~
$ (cd 'E:/test' ; ls ;)
wjSDR2
再测试一下不相同的情况,我在E:/test目录下,创建10个不相同的文件,每个文件内包含自己的文件名:
hp@hp-PC ~
$ (cd 'E:/test'; i=0; while [ "$i" -lt 10 ] ; do name=`mktemp "./XXXXXX"` ; echo "$name" > "$name" ; i=$((i+1)) ; done)hp@hp-PC ~
$ ./dupfile.sh 'E:/test'
26288eeea00c650ae612dcf5b0efa5ab E:/test/wBMk5c
6f28a86738b227553b116914befd7b55 E:/test/lOT1Yd
1bc7d2563796cf63c7f0d68affb190ef E:/test/haDFBY
679bc5d2d3e17761185ed82d43fd7d4a E:/test/CHOmSd
aaefa81fafd87bf3c3378ef02e22ef5a E:/test/yZ635B
e13b59ae07a9fd0e0a8095701c4003b2 E:/test/QdWtsN
ae2eabc1232111d9f12190b3a62d60bf E:/test/13PWOU
621d060c7c313f06eff1ce21a6b25f0c E:/test/sql7KV
7108830bbf019166d4af9a10030384f3 E:/test/lxGd5y
6dc2d2815a69f8a754503f1301e1cbcb E:/test/efUo7c
Total: 10 files
看到,列出的全部是不相同的文件,当文件数目比较多的时候,可以使用-s选项,静默输出,只列出重复的文件,不重复的文件则不列出。
最后,有个耐人寻味的问题,我在测试中发现,dupfile程序最后的管道末端的 tee >(....) 命令会莫名奇妙的终止,脚本的退出码为141,对应的是SIGPIPE信号。
我原先的脚本最后是这样写的:
tee >(if [ "$del" -eq 1 ]thenxargs rm -ffi)
分析得到,>( ... ) 这样的进程替换的实现原理是通过命名管道来做的,首先将 >( ... ) 此位置替换为 /dev/fd/63 或其他的命名管道文件,然后启动新的bash程序,来执行 >( ... ) 中的命令部分,而且bash程序的标准输入被替换为 /dev/fd/63 的管道输出端。而此时,为什么会触发SIGPIPE信号?
括号内部的命令部分是个判断语句,当判断为否定的时候,xargs命令不会执行,因此启动的bash程序就退出了,此时就造成,tee命令向 /dev/fd/63 这个管道端写的时候收到SIGPIPE信号,改正的做法是,要么保证 启动的bash程序不会退出,加一个else语句,tee >/dev/null ,要么就是忽略SIGPIPE信号,加上trap "" SIGPIPE就可以,同时将tee命令的stderr输出忽略 tee 2>/dev/null > ( ... )。
shell脚本实现查找文件夹下重复的文件,并提供删除功能相关推荐
- python查找文件夹中的指定文件_python 递归搜索文件夹下的指定文件
python 递归搜索文件夹下的指定文件 import os def look_in_directory(directory): """Loop through the ...
- python下载文件到指定文件夹-python实现指定文件夹下的指定文件移动到指定位置...
# coding:utf-8 import os import shutil import sys reload(sys) sys.setdefaultencoding('utf8') # print ...
- python保存文件到指定文件夹_python实现指定文件夹下的指定文件移动到指定位置...
本文主要是写了一个将指定文件夹下的指定文件类型移动到指定位置,具体内容如下 # coding:utf-8 import os import shutil import sys reload(sys) ...
- python指定文件路径_python实现指定文件夹下的指定文件移动到指定位置
# coding:utf-8 import os import shutil import sys reload(sys) sys.setdefaultencoding('utf8') # print ...
- java命令 jar文件夹_java中jar命令打包一个文件夹下的所有文件
(1)首先,必须保证java的所有路径都设置好,在dos提示符下输入jar -help 出现C:\Documents and Settings\dly>jar -help 非法选项:h 用法:j ...
- Linux下提取文件夹下的所有文件名称
Linux下提取文件夹下的所有文件名称 shell脚本 命令行建立一个.sh文件,并键入如下代码: #!/bin/bashpath=$1 #列出文件名 files=$(ls $path)for fil ...
- android 获取文件夹下的所有文件
昨天,在做工作时,需要遍历所有一个文件夹下的所有文件夹,当时自己也不知道怎么做,后来在网上搜索了一些资料,发现其实也很简单. 1.获取SD是否可以读写,如果可以,则传入文件的路径 /*读取输入的某个文 ...
- java 文件 递归_JAVA实现遍历文件夹下的所有文件(递归调用和非递归调用)
JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...
- 图解python pdf_Python合并同一个文件夹下所有PDF文件的方法
一.需求说明 下载了网易云课堂的吴恩达免费的深度学习的pdf文档,但是每一节是一个pdf,我把这些PDF文档放在一个文件夹下,希望合并成一个PDF文件.于是写了一个python程序,很好的解决了这个问 ...
最新文章
- 投影转换_即插即用,办公投影不用愁:毕亚兹Mini DP转HDMIVGA转换器
- 一种电子病历系统软件框架思想
- 有条件截取字符串_Python小课堂之木辛老师特别讲解:再次深入浅出字符串的格式化...
- 贪心,POJ(2709)
- Mocha Pro 2020中文版
- linux一键重装系统脚本,一键重装CentOS纯净版系统shell脚本
- HDU 6070 Dirt Ratio(线段树、二分)
- Mysql数据库基础系列(二):表结构、键值
- conn.execute的用法
- python--open用法
- 如何获取一个dll的cwinapp对象_一个女孩子是如何和暧昧对象确定恋爱关系的
- 蓝桥练习-算法训练 Collecting Luggage
- Excel模板导出之导出教材订购表
- 查询某表所有列名的SQL语句
- Linux:yum配置和使用
- 电脑测试软件_科普丨电脑小白必看的显卡测试小技巧
- css设置自适应屏幕高度
- LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想
- python连数据库课程设计报告_sql数据库课程设计报告书
- 上海企业英语培训机构排名