jq拼接含{}*""等特殊字符字符串报语法错误的解决方法
报错根本原因
- 核心是两层转义冲突:
- Shell引号解析冲突:之前的jq命令用双引号包裹整个过滤表达式,待拼接片段里自带的双引号会被Shell识别为字符串结束标记,实际传给jq的表达式是被截断的残缺内容,
*、{}这类字符在截断的位置会被jq判定为非法语法标记。 - jq语法转义错误:jq的双引号字符串规则要求,字面量双引号、字面量反斜杠必须用反斜杠转义,之前写法里的
\{属于无效转义;另外尝试的@text是jq的格式化过滤器,不是字面量定义关键字,直接放在表达式开头本身就不符合语法规则。
- Shell引号解析冲突:之前的jq命令用双引号包裹整个过滤表达式,待拼接片段里自带的双引号会被Shell识别为字符串结束标记,实际传给jq的表达式是被截断的残缺内容,
- 直接用
+=做拼接时,如果遍历到的target不存在expr字段、或者expr值为null,还会抛出null运算的额外错误。
正确实现方案
最稳妥的方案是用jq的--arg参数传入待拼接片段,彻底绕开Shell和jq的双重转义问题,不需要手动给特殊字符加转义,可直接运行:
# 定义待追加的PromQL片段,原样写入即可,不需要额外转义 APPEND_CONTENT='") * on(instance, process_id) group_left(name, display_name, run_as) windows_service_info\{display_name=~"$variable",job="$job"})' # 执行修改,结果输出到新文件避免覆盖原文件 jq --arg append_snippet "$APPEND_CONTENT" ' .dashboard.panels[].targets[].expr |= if contains("sum((rate(wmi") then . + $append_snippet else . end ' input_grafana.json > modified_grafana.json
方案说明:
- 整个jq过滤表达式用单引号包裹,Shell不会解析表达式内部的任何字符,从根源避免引号截断问题
- 待拼接内容通过
--arg作为字符串变量传入jq上下文,不需要在表达式里硬编码带特殊字符的字符串,完全避开双引号、反斜杠的转义坑 - 用
|=更新运算符配合if/else判断,仅修改符合筛选规则的expr字段,匹配不到的字段会保持原值,不会触发null运算错误
如果需要写单行硬编码命令(不推荐,维护性差容易写错),需要同时满足Shell单引号包裹、jq内部特殊字符转义的要求,写法参考:
jq '(.dashboard.panels[].targets[].expr | select(contains("sum((rate(wmi")))) += ") * on(instance, process_id) group_left(name, display_name, run_as) windows_service_info\\{display_name=~\"$variable\",job=\"$job\"})" input_grafana.json
注意硬编码写法里,字面量反斜杠要写\\(jq层面转义),字面量双引号要写\"(jq字符串层面转义)。
内容的提问来源于stack exchange,提问作者Nicholas Tripp
相关产品推荐
相关产品推荐

