为何find命令的-exec参数未传递所有文件与符号链接作为输入?
问题:find结合-exec执行md5sum仅返回部分文件的MD5值
场景重现
当前目录下的文件列表:
./02.tdf/IP_B186.tdf ./02.tdf/In_B186.tdf ./03.bed/IP_B186_vs_In_B186_peaks.xls.promoter_peak.bed ./03.bed/IP_B186_vs_In_B186_peaks.xls.bed ./01.genome/Harukei3_v1.41.fa ./01.genome/Harukei3_v1.41.gene.bed ./md5.txt
执行以下命令后,仅得到01.genome目录下两个文件的MD5值:
find . -type f -o -type l -exec md5sum {} + | sort > md5.txt
输出结果:
331a1bebdaf8b09fbdb6468b9c53bac3 ./01.genome/Harukei3_v1.41.fa 6354c1dfb5b0aff9620712ec17c271e3 ./01.genome/Harukei3_v1.41.gene.bed
而使用管道+while循环的命令能正常获取所有文件的MD5值:
find . -type f -o -type l | while read i; do md5sum $i >> md5.txt; done
输出结果:
d9eb8d2ad4f0c03ca1dc9628e3562f01 ./02.tdf/IP_B186.tdf c72eda337f2d75301baf125d6d64a5bc ./02.tdf/In_B186.tdf 3ea65045235ed51efcc88af49d126a60 ./03.bed/IP_B186_vs_In_B186_peaks.xls.promoter_peak.bed 954484488dce3f5f18b7c06f6693f223 ./03.bed/IP_B186_vs_In_B186_peaks.xls.bed 331a1bebdaf8b09fbdb6468b9c53bac3 ./01.genome/Harukei3_v1.41.fa 6354c1dfb5b0aff9620712ec17c271e3 ./01.genome/Harukei3_v1.41.gene.bed
同时,使用-exec md5sum {} \;的写法也返回不完整结果。
原因分析
问题核心是find命令的表达式优先级:-o(逻辑或)的优先级低于默认的逻辑与(-a,可省略),因此原命令被解析为:
find . -type f -o \( -type l -exec md5sum {} + \)
这意味着:
- 匹配
-type f的普通文件:仅触发find的默认动作-print,输出文件名,不会传给md5sum处理; - 匹配
-type l的符号链接:才会执行-exec调用md5sum。
你的场景中没有符号链接,理论上md5sum不会被执行,但实际结果中出现部分文件的MD5值,大概率是因为执行命令前md5.txt已存在旧内容,且> md5.txt的覆盖操作与find的文件遍历存在时序问题(find先读取了未被完全覆盖的md5.txt内容)。
解决方法
给-type f -o -type l加上括号,让-exec作用于所有匹配这两个条件的文件:
find . \( -type f -o -type l \) -exec md5sum {} + | sort > md5.txt
括号强制让-type f和-type l作为一个整体,-exec会处理所有符合该条件的文件,最终得到完整的MD5值列表。
内容的提问来源于stack exchange,提问作者ManJi
相关产品推荐
相关产品推荐

