Bash循环中变量自增失效问题求助
问题原因
bash中,管道(|)会创建子shell来执行管道右侧的命令。你脚本里的while read循环运行在子shell中,循环内对ccctr的修改只在子shell生效,父shell的ccctr变量不会被更新,所以最后输出的始终是初始值。
解决方案
有几种方法可以解决这个问题,推荐优先使用进程替换或直接优化find的调用方式,避免子shell:
方法1:用进程替换替代管道
把管道替换为进程重定向(< <(...)),这样while循环会在当前shell中执行,变量修改会保留:
#!/bin/bash cd /target # 创建计数器 ccctr=1 echo counter = $ccctr # 遍历所有目录(直接用find的进程替换,避免中间变量) while read -r -d '' a do # 遍历当前目录下的文件(同样用进程替换) while read -r -d '' b do let "ccctr=ccctr+1" ##shasha=$(shasum -a 512 "$b") shasha="$b" echo b: $shasha done < <(find "$a" ! -name '.DS_Store' ! -name '.localized' -maxdepth 1 -type f -print0) echo --------$ccctr total Files Found done < <(find . -type d -print0)
这里直接用find ... -print0配合read -r -d ''来处理含空格的文件名,比存到变量再echo更可靠,也避免了中间变量的冗余。
方法2:启用lastpipe选项(bash 4.2及以上版本)
如果你的bash版本≥4.2,可以开启lastpipe选项,让管道最后一个命令在当前shell执行:
#!/bin/bash shopt -s lastpipe cd /target ccctr=1 echo counter = $ccctr allD=$(find . -type d -print0 | xargs -0 -n 1 echo) echo "$allD" | while read -r a do allF=$(find "$a" ! -name '.DS_Store' ! -name '.localized' -maxdepth 1 -type f -print0| xargs -0 -n 1 echo) echo "$allF" | while read -r b do let "ccctr=ccctr+1" ##shasha=$(shasum -a 512 "$b") shasha="$b" echo b: $shasha done echo --------$ccctr total Files Found done
这种方法改动最小,但依赖bash版本。
方法3:用文件存储计数器(兼容所有bash版本)
如果以上方法都不可用,可以把计数器的值存到临时文件中,每次读取和更新:
#!/bin/bash cd /target # 创建临时文件存计数器 temp_file=$(mktemp) echo 1 > "$temp_file" ccctr=$(cat "$temp_file") echo counter = $ccctr allD=$(find . -type d -print0 | xargs -0 -n 1 echo) echo "$allD" | while read -r a do allF=$(find "$a" ! -name '.DS_Store' ! -name '.localized' -maxdepth 1 -type f -print0| xargs -0 -n 1 echo) echo "$allF" | while read -r b do # 从临时文件读值,自增后写回 ccctr=$(cat "$temp_file") let "ccctr=ccctr+1" echo "$ccctr" > "$temp_file" ##shasha=$(shasum -a 512 "$b") shasha="$b" echo b: $shasha done ccctr=$(cat "$temp_file") echo --------$ccctr total Files Found done # 清理临时文件 rm "$temp_file"
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

