如何修改Bash脚本实现日索引自增并保持两位格式?
解决CDO减法生成RAIN前缀NC文件的日期格式问题
原写法${j+1}是bash的参数扩展语法,并非算术自增逻辑,即便改用算术表达式$((j+1)),也会存在两个核心问题:
- 计算结果不会自动补零,比如1会显示为
1而非01; - 带前导零的数字(如
08、09)会被bash视为八进制数,直接运算会报错。
以下提供两种可行解决方案:
推荐方案:基于现有文件列表自动匹配(无需手动处理日期)
这种方法无需手动计算日期,直接利用已按日期排序的文件列表,自动匹配前一日和当日文件,完全避免日期计算的错误(比如跨月、八进制数字问题)。
#!/bin/bash # 获取所有TOTAL前缀的NC文件,并按日期排序(确保顺序正确) sorted_files=($(ls -1 TOTAL_summer_*.nc | sort)) # 从第二个文件开始遍历,与前一个文件执行减法 for ((idx=1; idx<${#sorted_files[@]}; idx++)); do prev_file="${sorted_files[idx-1]}" curr_file="${sorted_files[idx]}" # 提取当前文件的日期字符串(如2003-06-01) curr_date=$(echo "$curr_file" | sed -E 's/TOTAL_summer_([0-9]{4}-[0-9]{2}-[0-9]{2})\.nc/\1/') # 生成输出文件名 output_file="RAIN_summer_${curr_date}.nc" # 执行CDO减法:当日文件 - 前一日文件(假设TOTAL为累积量,差值为当日降水) cdo sub "$curr_file" "$prev_file" "$output_file" echo "已生成: $output_file" done
方案优势:
- 自动处理所有日期场景,包括跨月(如6月30日→7月1日),无需额外判断;
- 完全避免前导零、八进制数字的运算错误;
- 只需确保文件命名规范且存在,无需手动指定日期范围。
备选方案:手动日期循环(需处理补零与跨月)
如果需要手动指定日期范围,可通过printf实现数字补零,同时处理跨月场景:
#!/bin/bash # 定义日期参数 target_year="2003" target_month="06" start_day=1 end_day=30 for ((day=start_day; day<=end_day; day++)); do # 生成当日的两位格式日期 curr_day=$(printf "%02d" "$day") # 处理前一日日期:1号对应上月最后一天,此处以5月31日为例,需根据实际月份调整 if [ "$day" -eq 1 ]; then prev_month="05" prev_day="31" else prev_month="$target_month" prev_day=$(printf "%02d" "$((day-1))") fi # 拼接文件名 prev_file="TOTAL_summer_${target_year}-${prev_month}-${prev_day}.nc" curr_file="TOTAL_summer_${target_year}-${target_month}-${curr_day}.nc" output_file="RAIN_summer_${target_year}-${target_month}-${curr_day}.nc" # 检查文件是否存在,再执行CDO命令 if [ -f "$prev_file" ] && [ -f "$curr_file" ]; then cdo sub "$curr_file" "$prev_file" "$output_file" echo "已生成: $output_file" else echo "跳过:文件不存在 - $prev_file 或 $curr_file" fi done
注意事项:
- 跨月场景需要手动指定上月最后一天,如需处理多个月份,需额外添加月份判断逻辑;
- 避免使用带前导零的数字直接做算术运算(如
08会被bash视为八进制,导致运算失败),必须先用printf处理或转为十进制。
内容的提问来源于stack exchange,提问作者climsaver
相关产品推荐
相关产品推荐

