如何使用Bash提取代码行版本字符串存入$VERSION,解决awk返回冗余内容问题
作为脚本开发新手,当前需要完成的开发任务如下:
- 从C/C++源码的宏定义行(目标行示例:
#define PROJECT_VERSION "21.02")中提取双引号包裹的版本字符串 - 将提取到的纯版本值(如示例中的
21.02)存入Bash环境的$VERSION变量 - 现有实现命令
awk '/PROJECT_VERSION/{print $NF}' common/ESUtils.cpp存在输出夹带多余字符串的问题,需要可靠的可落地Bash处理方案。
原命令的核心缺陷有两点:
- 匹配规则过宽:只要行内出现
PROJECT_VERSION字样就会触发处理,可能误匹配注释、业务代码中出现的同名变量行 - 取值逻辑粗糙:用
$NF取最后一个空格分隔字段,会直接把字符串自带的双引号、行尾附带的代码注释一起返回,无法直接作为版本值使用。
根据场景鲁棒性需求不同,可以选择以下任意一种实现:
适配现有awk使用习惯的轻量调整版
保留awk的处理逻辑,补充匹配规则、剥离多余引号:VERSION=$(awk '/^#define[[:space:]]+PROJECT_VERSION[[:space:]]+/{gsub(/"/, "", $NF); print $NF}' common/ESUtils.cpp)
调整点说明:
- 增加行首锚定
^#define,严格匹配宏定义行,避免误匹配业务代码、注释中的同类字样 - 用
gsub(/"/, "", $NF)移除字段内的所有双引号,直接输出纯版本值。
适配复杂场景的高鲁棒版本
如果目标宏定义行后可能附带行尾注释(如#define PROJECT_VERSION "21.02" // 2024年迭代版本),上面取最后一个字段的方式仍会夹带注释内容,此时推荐用grep的精确匹配规则,直接从双引号间隙提取内容,不受行尾多余内容干扰:VERSION=$(grep -oP '#define\s+PROJECT_VERSION\s+"\K[^"]+' common/ESUtils.cpp)
该规则的执行逻辑:
- 先严格匹配宏定义的固定格式
- 用
\K丢弃前面已经匹配到的固定字符串部分 - 直接抓取第一个双引号之后、下一个双引号之前的所有字符,输出的就是完全纯净的版本值,不需要额外做符号剥离。
Sed备选实现
如果环境中没有支持-P参数的grep,可以用sed的正则捕获能力实现同等效果:VERSION=$(sed -n '/^#define[[:space:]]*PROJECT_VERSION[[:space:]]*"\([^"]*\)"/s/.*"\([^"]*\)".*/\1/p' common/ESUtils.cpp)
注意:所有方案都通过命令替换
$(...)直接将提取结果赋值给$VERSION变量,执行完成后可以直接用echo $VERSION验证输出是否符合预期。
内容的提问来源于stack exchange,提问作者Mihnea Cristian Marin

