![查找并删除目录层次结构中的重复文件名](https://linux22.com/image/605555/%E6%9F%A5%E6%89%BE%E5%B9%B6%E5%88%A0%E9%99%A4%E7%9B%AE%E5%BD%95%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E6%96%87%E4%BB%B6%E5%90%8D.png)
#!/bin/sh
LASTBASE=""
find $1 -type f -print | rev | sort | rev | while read FILE
do
BASE=$(basename "$FILE")
if [ "$BASE" = "$LASTBASE" ]; then
rm "$FILE"
LASTBASE="$BASE"
done
答案1
如果将输出放入循环find
中,while read
则可以逐行处理它们:
find nnn/ -type f -print | rev | sort | rev | while read FILE; do
...
done
编辑:因此,如果文件名包含双(连续)空格,此方法确实会中断,因为read
实际上会根据拆分行$IFS
,然后在存储最后一个变量时再次将其连接起来。为了解决这个问题,您可以暂时更改$IFS
为禁用拆分:
OIFS="$IFS"
IFS=""
find | while read...
IFS="$OIFS"
编辑: test
(与 相同[
)没有==
运算符,您只需要=
。
答案2
我刚刚在旧的 bash 历史记录中发现了这个“宝石”,它实际上可以正常工作,而不会在文件名中遇到空格。
内容比较
for hash in `find . -exec md5sum {} \; 2>/dev/null | sort | awk '{ print $1 }' | uniq -d`; do
find . -exec md5sum {} \; 2>/dev/null | grep $hash | awk '{print $2 }';
done;
非正式:
- 第一行:遍历目录树并计算下面所有文件的 md5sum,对此输出进行排序(格式:哈希文件名),抓取哈希列,将其减少为双倍的值。(意味着有重复)
- 第二行:对于每个重复出现的哈希值,再次遍历并打印文件名,如果当前文件具有当前哈希值(意味着该文件是多个文件之一)
示例输出:
./aFile
./aFolder/aFile
./1000digitsOfPI
./a/b/c/thousanddigitsofPI
./b File
./bFolder/cFolder/b File
这里不执行删除操作,因为可能很难决定要保留哪个版本的重复文件。
按文件名比较
如果您只想查看文件名而不是内容,那就更简单了:
for name in `find . -type f -printf "%f\n" | sort | uniq -d`; do
find . -name $name;
done;
更新:不幸的是,此版本再次因文件名中的空格而出现问题。
答案3
问题就出在这行代码上for FILE in $FILES; do
- for 循环根据空格分隔符分配 FILE 变量。因此,如果文件有一个或多个空格,它将无法工作。只需将默认 IFS 从空格更改为新行或制表符即可。如果我没记错的话,你可以在 bash 中使用类似这样的代码设置 IFS -
IFS=$'\n'