如何用jq遍历字符串正则匹配结果并生成关联控制数组?
jq提取JSON中关联控制字符串到数组的解决方案
需求说明
从JSON的description字段中提取"Related controls:"后的控制字符串,转移到新的relatedControls数组中,并移除原description里的对应内容。
输入JSON
{"description": "Fail-safe procedures include, for example, alerting operator personnel and providing specific instructions on subsequent steps to take (e.g., do nothing, re-establish system settings, shut down processes, restart the system, or contact designated organizational personnel). Related controls: CA-2, CA-7, CM-3, CM-5, CM-8, MA-2, IR-4, RA-5, SA-10, SA-1x, SI-1x"}
期望输出JSON
{"description": "Fail-safe procedures include, for example, alerting operator personnel and providing specific instructions on subsequent steps to take (e.g., do nothing, re-establish system settings, shut down processes, restart the system, or contact designated organizational personnel).", "relatedControls": ["CA-2", "CA-7", "CM-3", "CM-5", "CM-8", "MA-2", "IR-4", "RA-5", "SA-10", "SA-1x", "SI-1x"]}
原命令问题分析
原命令的核心问题是正则表达式匹配逻辑不严谨:
原正则[A-Z]{2}-\\d[0-9x]?仅匹配"单个数字+可选单个数字/x"的组合,虽能覆盖当前示例,但对于更长数字后缀的控制符(如AB-123)会无法完整匹配,且存在拆分匹配结果的风险。
修正方案
方案1:精准捕获拆分(推荐)
通过capture直接定位并拆分目标内容,避免全局扫描可能带来的误匹配:
jq ' .description |= capture("(?<desc>.*?) Related controls: (?<controls>.*)") | .description = .desc | .relatedControls = (.controls | split(", ") | map(trim)) '
命令解释:
capture将description拆分为两部分:desc(控制符前的纯描述文本)和controls(控制符列表字符串);- 替换原
description字段为纯描述内容; - 将控制符字符串按
,分割为数组,并用map(trim)清理可能存在的首尾空格。
方案2:修正正则后的全局扫描
如果偏好使用scan,可调整正则表达式以覆盖所有目标格式:
jq ' { description: .description | sub(" Related controls:.*"; ""), relatedControls: .description | scan("[A-Z]{2}-\\d+x?") } '
正则说明:
[A-Z]{2}-\\d+x?表示:两位大写字母 + 连字符 + 一个或多个数字 + 可选的x结尾,能准确匹配所有目标控制符。
验证命令
echo '{"description": "Fail-safe procedures include, for example, alerting operator personnel and providing specific instructions on subsequent steps to take (e.g., do nothing, re-establish system settings, shut down processes, restart the system, or contact designated organizational personnel). Related controls: CA-2, CA-7, CM-3, CM-5, CM-8, MA-2, IR-4, RA-5, SA-10, SA-1x, SI-1x"}' | jq ' .description |= capture("(?<desc>.*?) Related controls: (?<controls>.*)") | .description = .desc | .relatedControls = (.controls | split(", ") | map(trim)) '
内容的提问来源于stack exchange,提问作者mikewilliamson
相关产品推荐
相关产品推荐

