嵌套for循环执行异常:仅对最后下载的id执行一次匹配校验
问题根因分析
你遇到的问题是shell脚本常见的语法和运行机制坑,核心原因有4个:
- 管道触发子shell执行:
sed 1d $csvfile | while IFS=, read ...这种写法在bash、dash等常用shell中,管道右侧的while循环会在独立子shell中运行,如果后续逻辑有异常终止操作,或者依赖外层变量的判断,很容易导致循环只跑一次就退出 - CSV换行符不兼容:如果你的CSV是Windows系统生成的,行尾是
\r\n格式,你只处理了单个字段的\r,但read读行时会把行尾的\r识别为有效字符,轻则导致最后一个字段异常,重则直接触发read提前终止,只读第一行 - 静默执行无错误捕获:wget加了
-q参数吞掉了所有错误,如果前面的站点下载索引失败,你看不到报错,会误以为循环没有执行 - 代码语法缺失:你贴出的代码里
checkIndex函数没有闭合的},while循环也没有闭合的done,如果实际运行的代码也是这个状态,会出现语法异常,只执行到第一个循环就终止
排查步骤
- 先验证CSV读取逻辑:在while循环第一行加
echo "当前读取行:$site $id $key $url $conf",执行脚本看打印次数和CSV条目数是否一致,确认循环有没有跑完全部条目 - 去掉wget的
-q参数,或者在wget后加判断if [ $? -ne 0 ]; then echo "站点$site索引下载失败"; fi,确认每个站点的索引文件是否下载成功 - 检查CSV文件格式:执行
cat -A $csvfile看行尾是不是^M$(也就是\r\n),如果是的话先执行dos2unix $csvfile转换为Unix格式
修复方案
1. 调整循环写法避免子shell
把管道写法改成进程替换+输入重定向,让while循环在当前shell执行,同时统一处理CSV里的所有\r字符:
# 替换原来的sed+管道循环写法 while IFS=, read -r site id key url conf do # 原有业务逻辑 done < <(sed '1d;s/\r//g' "$csvfile")
2. 补全语法加错误判断
补全函数和循环的闭合语法,给所有文件操作、下载操作加错误捕获,避免静默失败,同时给所有变量加双引号避免空格异常:
checkIndex() { # 入参和文件校验 if [ $# -ne 3 ] || [ ! -f "$2/$3/logs.index" ]; then return 0 fi local temp=$(echo "$1" | tr -d '\r') # 替换for循环读取索引的写法,避免特殊字符拆分错误 while read -r log do log=$(echo "$log" | tr -d '\r') if [ "$temp" == "$log" ]; then return 1 fi done < "$2/$3/logs.index" return 0 } # 循环部分完整实现 while IFS=, read -r site id key url conf do # 校验当前下载ID文件是否存在 curr_file="$CONF_DIR$conf/LastKnownDownloadedFileId_curr.txt" if [ ! -f "$curr_file" ]; then echo "配置文件$curr_file不存在,跳过当前条目" continue fi curr=$(cat "$curr_file") site=$(echo "$site" | tr -d '\r') id=$(echo "$id" | tr -d '\r') key=$(echo "$key" | tr -d '\r') url=$(echo "$url" | tr -d '\r') index="logs.index" echo "$site $id $key $url $conf" # 目录创建加错误判断 if [ ! -d "$TEMPDIR/$site" ]; then mkdir -p "$TEMPDIR/$site" || { echo "创建目录$TEMPDIR/$site失败,跳过"; continue; } fi # 下载加错误判断 wget -q --user="$id" --password="$key" "$url$index" -O "$TEMPDIR/$site/logs.index" if [ $? -ne 0 ]; then echo "站点$site索引下载失败,跳过" continue fi # 处理校验结果 checkIndex "$curr" "$TEMPDIR" "$site" if [ $? -eq 1 ]; then echo "$curr 在索引中存在" else echo "$curr 在索引中不存在" fi done < <(sed '1d;s/\r//g' "$csvfile")
内容的提问来源于stack exchange,提问作者gzgodz
相关产品推荐
相关产品推荐

