You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

统计gcc源码C文件总大小时bash循环无法终止问题

GCC源码统计脚本统计.c文件卡死问题

问题复现

计划分类统计GCC 11.2.0的源码规模,先编写脚本统计cpp类型文件,代码如下:

# NOTE: the cpp loop finishes immediately
LOC=0
BYTES=0
FILES=$(find . -name "*.cpp")
for f in ${FILES};
do
    BYTES_TAG=$(stat --printf="%d" $f)
    LOC_TAG=$(cat $f | wc -l)
    BYTES=$((BYTES+BYTES_TAG))
    LOC=$((LOC+LOC_TAG))
done
echo "LOC = $LOC, SIZE = $BYTES"

统计cpp文件时脚本瞬间执行完成,但将匹配规则改为*.c统计所有C文件时,bash循环长时间无响应、无法终止。
测试环境下源码为官方解压的原始包,未做额外修改,执行全量文件计数命令时可以瞬间返回结果:

find . -type f | wc -l

核心原因

脚本本身存在多处逻辑缺陷,叠加GCC源码的文件结构特点导致了假卡死现象:

  • 文件遍历写法有缺陷:直接将find结果存入变量、用不带引号的for f in ${FILES}遍历,完全没有处理带特殊字符(空格、换行、通配符)的文件名,一旦文件名被拆分出特殊值(比如单独的-),cat命令会进入等待标准输入的状态,直接挂住整个循环。
  • 逐文件调用命令的开销被量级放大:GCC源码中cpp文件仅千余个,每个文件单独调用stat、cat、wc的进程开销感知不明显;但源码中.c文件数量达数万个,高频创建进程的开销会让脚本运行速度暴跌,看起来和卡死无异。
  • 额外逻辑bug:stat --printf="%d"获取的是文件所在设备的ID,不是文件字节数,要统计文件大小应该用%s参数;find命令未加-type f参数,会匹配到目录、符号链接等非普通文件,进一步增加无效遍历。
  • find . -type f | wc -l运行速度快的原因是该命令为管道流式处理,不需要把所有文件路径存到变量里,也不需要对每个文件单独启动额外进程,自然执行效率极高。

修正方案

不要用逐文件起进程的循环写法,直接用find配合批量处理命令,效率会提升两个数量级以上:

# 统计cpp文件
echo "cpp文件统计:"
find . -type f -name "*.cpp" -print0 | du --files0-from=- -c -b | tail -n1
find . -type f -name "*.cpp" -print0 | xargs -0 wc -l | tail -n1

# 统计c文件
echo "c文件统计:"
find . -type f -name "*.c" -print0 | du --files0-from=- -c -b | tail -n1
find . -type f -name "*.c" -print0 | xargs -0 wc -l | tail -n1

如果一定要保留循环写法,必须用兼容特殊文件名的遍历逻辑,同时修正参数错误:

LOC=0
BYTES=0
# -print0和read -d ''配合,兼容所有合法文件名
find . -type f -name "*.c" -print0 | while IFS= read -r -d '' f; do
    BYTES=$((BYTES + $(stat -c "%s" "$f")))
    LOC=$((LOC + $(wc -l < "$f")))
done
echo "LOC = $LOC, SIZE = $BYTES"

内容的提问来源于stack exchange,提问作者OrenIshShalom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:57:10