管道后子shell中while循环失效:Git代码行统计脚本问题
解决Git作者代码增删行数统计汇总的问题
看起来你的脚本遇到了两个核心问题,导致汇总结果全为0还出现语法错误,咱们一步步拆解解决:
问题根源分析
- 无关输出混入管道:你前面的
echo "Listing file and line changes for $author"会把文本输出到标准输出(stdout),跟着awk的结果一起进入后面的子shell。当read changed insertions deletions读取到这些非数字行时,let命令自然会报错——它没法处理"line changes for Benjamin Hills"这种字符串。 - awk输出格式不匹配:你的awk输出的是带描述文本的完整句子,比如
files changed: 61 lines removed: 1345 lines added: 246 net change: -1099,但read期望的是三个单独的数值,根本没法正确提取出changed、insertions、deletions的数值,所以总和一直是0。
修复方案
1. 调整awk输出,只输出纯数值
把awk的END块改成只输出我们需要的三个数值,用空格分隔,让read能准确读取:
END{ print changed, insertions, deletions }
2. 把状态提示输出到stderr,避免进入管道
把前面的echo语句重定向到标准错误流(stderr),这样它不会被管道传到汇总子shell里:
echo "Listing file and line changes for $author" >&2
3. 优化汇总子shell的算术运算逻辑
换成bash更现代的(( ))算术写法,语法更直观,容错性也更好:
(( total_changed += changed )) (( total_added += insertions )) (( total_removed += deletions ))
修改后的完整脚本
for author; do # 把提示信息输出到stderr,不干扰管道内的统计数据 echo "Listing file and line changes for $author" >&2 git log --shortstat --author="$author" ${date:+--since="$date"} \ | sed -n -e '/files\? changed/s/, /\n/gp' \ | awk ' $3=="changed" {changed+=$1} $2=="deletions(-)" {deletions+=$1} $2=="insertions(+)" {insertions+=$1} END{ print changed, insertions, deletions }' done | { total_changed=0 total_added=0 total_removed=0 while read changed insertions deletions; do (( total_changed += changed )) (( total_added += insertions )) (( total_removed += deletions )) done echo "totals:" echo "files changed: $total_changed" echo "lines added: $total_added" echo "lines removed: $total_removed" }
效果说明
现在管道里只会传递awk输出的三个数值行,read能准确解析每行数据,算术运算也不会再报错,最后就能得到正确的汇总结果了。测试时,你会先看到stderr输出的作者统计提示,最后输出正确的总行数和文件数汇总。
内容的提问来源于stack exchange,提问作者Benjamin Hills
相关产品推荐
相关产品推荐

