【问题标题】:jq bash issue with filtering with CONTAINS使用 CONTAINS 过滤的 jq bash 问题
【发布时间】:2026-01-05 19:20:02
【问题描述】:

我有一个问题,我试图过滤带有 CONTAINS 的记录,但它不接受其中包含空格的变量。我包括 JSON 和调用。我解释什么有效,最后一个无效。我看过高和低,但我无法让它工作。我已经看到并尝试了很多(考虑到双引号的数百种方法,转义,不转义,有,没有,但没有运气)有人可以看看并指出我可能有帮助的东西。

用于测试的 JSON

_metadatadashjson='{  "meta": {    "provisionedExternalId": ""  },  "dashboard": {    "liveNow": false,    "panels": [      {        "collapsed": false,        "title": "Gyrex Thread Count Gauges",        "type": "row", "targets": [          {            "expr": "jvm_threads_current{instance=\"192.1.50.22:8055\",job=\"prometheus_gyrex\"}",            "refId": "B"          }        ]      },      {        "datasource": "Prometheus_16_Docker",        "targets": [          {            "exemplar": true,            "expr": "jvm_threads_current{instance=\"10.32.0.4:8055\",job=\"prometheus_gyrex\"}"          }        ],        "title": ".16 : 3279",        "type": "gauge"      },      {        "description": "",        "targets": [          {            "expr": "jvm_threads_current{instance=\"10.32.0.7:8055\",job=\"prometheus_gyrex\"}",            "refId": "B"          }        ],        "title": ".16 : 3288",        "type": "graph"      },      {        "description": "",        "targets": [          {            "expr": "jvm_threads_current{instance=\"192.168.2.16:3288\",job=\"prometheus_gyrex\"}",            "refId": "C"          }        ],        "title": ".16 : 3288",        "type": "graph"      }    ],    "version": 55  }}'

设置要在键“expr”中搜索的字符串

exprStrSearch="10.32.0.4:8055"

此作品返回一条记录

echo "${_metadatadashjson}" | jq -r --arg EXPRSTRSEARCH "$exprStrSearch" '.dashboard.panels[] | select(.targets[].expr | contains($EXPRSTRSEARCH)) | .targets[].expr'

这工作没问题返回两条记录。

echo "${_metadatadashjson}" | jq -r --arg EXPRSTRSEARCH "$exprStrSearch" '.dashboard.panels[] | select(.targets[].expr | contains("10.32.0.4:8055", "10.32.0.7:8055")) | .targets[].expr'

更改值以包含空格和另一个字符串

exprStrSearch="10.32.0.4:8055 10.32.0.7:8055"

不起作用。

echo "${_metadatadashjson}" | jq -r --arg EXPRSTRSEARCH "$exprStrSearch" '.dashboard.panels[] | select(.targets[].expr | contains($EXPRSTRSEARCH)) | .targets[].expr'

【问题讨论】:

    标签: bash jq


    【解决方案1】:

    您的所有数据都不包含"10.32.0.4:8055 10.32.0.7:8055"

    您可以使用 bash 数组将多个字符串传递给 contains()

    strings=("10.32.0.4:8055" "10.32.0.7:8055")
    
    echo "${_metadatadashjson}" |
    jq -r --args '.dashboard.panels[] | select(.targets[].expr | contains($ARGS.positional[])) | .targets[].expr' "${strings[@]}"
    

    contains 将在每场比赛中评估为真。 IE。如果一个expr 包含两个字符串,它将被选择(并打印)两次。

    test 不会发生这种情况。以下是如何在多个字符串之间添加 |s,并将它们传递到单个 jq 变量中(以及转义所有点):

    strings=("10.32.0.4:8055" "10.32.0.7:8055")
    IFS=\|
    echo "${_metadatadashjson}" |
    jq -r --arg str "${strings[*]//./\\.}" '.dashboard.panels[] | select(.targets[].expr | test($str)) | .targets[].expr'
    

    两个例子都打印了这个:

    jvm_threads_current{instance="10.32.0.4:8055",job="prometheus_gyrex"}
    jvm_threads_current{instance="10.32.0.7:8055",job="prometheus_gyrex"}
    

    更新:我忘了为test 转义。我编辑了test 示例,以便所有点都被转义(使用一个反斜杠)。它是正则表达式,因此(未转义的)点将匹配任何字符。 contains 示例按字面意思匹配字符串(不是正则表达式)。

    【讨论】:

    • Dan,感谢您澄清了这个过程。我不敢相信我对CONTAINS的理解有多糟糕。我试过你的解决方案,它就像一个魅力。下面是我正确返回 3 条记录的结果。 exprStrSearch="10.32.0.4:8055|10.32.0.7:8055|192.168.2.16:3288" echo "${_metadatadashjson}" | jq -r --arg EXPRSTRSEARCH "$exprStrSearch" '.dashboard.panels[] |选择(.targets[].expr | 测试($EXPRSTRSEARCH)) | .targets[].expr'
    • @user3008410 很高兴它对你有用。请参阅我关于转义点的更新,我忘了这样做。您可以通过直接编写 "10\.32\.0" 等来实现这一点,或者使用 bash 模式替换添加它们:--arg EXPRSTRSEARCH "${exprStrSearch//./\\.}"
    • 是的,更新按预期工作;感谢您抽出宝贵时间!
    【解决方案2】:

    问题是带有空格的字符串实际上并没有出现在给定的 JSON 中。不太清楚您要做什么,但请注意 contains 不是对称的:

    "a" | contains("a b")
    

    计算为false

    如果你打算编写一个布尔搜索条件,你可以使用一个布尔表达式,或者使用 jq 的正则表达式机制,例如

    test("10.32.0.4:8055|10.32.0.7:8055")
    

    甚至可能更好:

    test("\"(10[.]32[.]0[.]4:8055|10[.]32[.]0[.]7:8055)\"")
    

    【讨论】:

    • 警告:在正则表达式中,. 表示“匹配任何单个字符”。我不明白这会如何在这里造成混乱,但我也不能保证它不会。