Bash脚本中let命令统计删除文件数未按预期工作求助
Bash函数统计删除文件数量变量重置问题解决方法
我编写了一个用于查找哈希码列表中重复项并删除对应文件的Bash函数,但统计删除文件数量的deleted_files变量未按预期工作——每处理一批重复项后变量就会重置,最终输出始终为0 files have been deleted。
原函数代码
delete_duplicates() { let deleted_files=0 echo "deleted_files $deleted_files" while read dup; do let count=1 grep "$dup" $1 | while read file_hash; do if [[ $count -eq 1 ]]; then let count++ continue else file="$(echo "$file_hash" | cut -d ' ' -f 3-)" rm "$file" if [[ $? != 0 ]]; then echo "Error deleting the file $file" exit 1 fi echo $deleted_files let deleted_files++ fi done done < $2 echo "${deleted_files} files have been deleted" }
调用代码
get_hash_list > $hash_list get_duplicates $hash_list > $duplicates delete_duplicates $hash_list $duplicates
执行输出示例
$ bash duplicateFinder.sh deleted_files 0 0 1 2 3 0 1 2 3 ... 0 files have been deleted
问题根源
Bash中管道会创建独立的子shell,grep "$dup" $1 | while read file_hash; do ... done这段代码里的while循环运行在子shell中。子shell会继承父shell的变量初始值,但子shell内对变量的修改不会同步回父shell。每处理一个重复哈希值,管道就会生成新的子shell,子shell结束后其内部的deleted_files增量会被丢弃,父shell中的deleted_files始终保持初始的0。
解决方法
方案1:用进程替换替代管道
进程替换可以让while循环在当前shell中执行,变量修改会直接保留在父shell中:
delete_duplicates() { let deleted_files=0 echo "deleted_files $deleted_files" while read dup; do let count=1 # 用进程替换替代管道,避免创建子shell while read file_hash; do if [[ $count -eq 1 ]]; then let count++ continue else file="$(echo "$file_hash" | cut -d ' ' -f 3-)" rm "$file" if [[ $? != 0 ]]; then echo "Error deleting the file $file" exit 1 fi echo $deleted_files let deleted_files++ fi done < <(grep "$dup" "$1") # 进程替换语法 done < "$2" echo "${deleted_files} files have been deleted" }
方案2:捕获子shell输出累加计数
如果你的Bash版本不支持进程替换,可以让子shell输出每次删除的增量,在父shell中累加统计:
delete_duplicates() { let deleted_files=0 echo "deleted_files $deleted_files" while read dup; do let count=1 # 捕获子shell中输出的删除次数 increment=$(grep "$dup" "$1" | while read file_hash; do if [[ $count -eq 1 ]]; then let count++ continue else file="$(echo "$file_hash" | cut -d ' ' -f 3-)" rm "$file" if [[ $? != 0 ]]; then echo "Error deleting the file $file" exit 1 fi echo 1 # 每次删除输出1表示增量 let count++ fi done | wc -l) # 统计输出行数即该哈希下的删除数量 let deleted_files+=increment # 模拟原输出的计数过程 for ((i=deleted_files-increment; i<deleted_files; i++)); do echo $i done done < "$2" echo "${deleted_files} files have been deleted" }
额外优化提示
- 变量引用加上双引号(如
"$1"、"$2"),避免文件名含空格或特殊字符时出错; - 可以用
$((deleted_files++))替代let deleted_files++,这是Bash更现代的算术扩展写法; - 可添加删除前的确认逻辑(可选),降低误删风险。
内容的提问来源于stack exchange,提问作者Jose Constenla
相关产品推荐
相关产品推荐

