在 bash 函数中参数化 jq 中的过滤器时的语法问题

问题描述 投票:0回答:1

我在

jq
脚本中使用
bash
来搜索可在 json 文件中任何位置找到的数组中的项目。我已经编写了一个具有解决问题的不良做法的函数。在编写更多使用
jq
的脚本之前,我想知道如何正确执行此操作。

这是一个 json 文件的示例,

silly-sample.json
:

{
  "fruits_with_a":[
    {"fruitName":"Apple","value":"..."},
    {"fruitName":"Apricot","value":"..."},
    {"fruitName":"Aratiles","value":"..."},
    {"fruitName":"Araza","value":"..."},
    {"fruitName":"Avocado","value":"..."}
  ],
  "fruits_with_b":[
    {"name":"Banana","value":"..."},
    {"name":"Blackberry","value":"..."},
    {"name":"Black sapote","value":"..."},
    {"name":"Blueberry","value":"..."},
    {"name":"Breadfruit","value":"..."}
  ],
  "fruits_with_c":[
    {"id":"Cherry","value":"..."},
    {"id":"Coconut","value":"..."},
    {"id":"Cranberry","value":"..."}
  ],
  "fruits_with_d":[
    {"sku":"Dragonfruit","value":"..."},
    {"sku":"Durian","value":"..."}
  ],
  "vegetables":{
    "with_a":[
      {"n":"artichoke","value":"..."},
      {"n":"aubergine","value":"..."},
      {"n":"asparagus","value":"..."}
    ],
    "with_b":[
      {"n":"broccoflower","value":"..."},
      {"n":"broccoli","value":"..."},
      {"n":"brussels sprouts","value":"..."}
    ],
    "with_c":[
      {"n":"cabbage","value":"..."},
      {"n":"cauliflower","value":"..."},
      {"n":"celery","value":"..."},
      {"n":"cichory","value":"..."}
    ]
  }
}

我执行的大多数搜索都非常简单并且遵循一定的模式。更改的参数是:我要执行搜索的 array、我要用于搜索的 field 以及我要搜索的 value。以下是我使用

jq
执行的查询的一些示例:

jq -r '.fruits_with_b[] | select(.name=="Blackberry")' "./silly-sample.json"

jq -r '.fruits_with_c[] | select(.id=="Coconut")' "./silly-sample.json"

jq -r '.vegetables.with_a[] | select(.n=="aubergine")' "./silly-sample.json"

如前所述,我创建了一个

bash
函数 (
retrieve_from_array
) 来概括我的脚本在数组中搜索项目的方式。当时我不知道使用
jq
将参数传递给
--arg
的正确方法,我最终所做的是将整个命令连接成一个字符串,然后使用 eval 执行它。到目前为止,该解决方案非常有效。

retrieve_from_array(){
  local jq_query jq_result && \
  jq_query="jq -r '.${1}[] | select(.${2}==\"${3}\")' \"./silly-sample.json\"" && \
  jq_result="$(eval "${jq_query}")" && \
  echo "${jq_result}" && \
  return 0

  return 1
}

retrieve_from_array "fruits_with_a" "fruitName" "Apricot" && echo "Executed successfully!!!"
retrieve_from_array "vegetables.with_a" "n" "asparagus" && echo "Executed successfully!!!"

现在我需要用

bash
编写更多
jq
函数,以执行更多条件的附加搜索。合乎逻辑的做法是继续使用字符串连接,并根据搜索需要添加更多条件、更多运算符和更多值,然后使用 eval 执行,但这似乎不是一个好的扩展实践。

我尝试通过使用

retrieve_from_array
将参数传递给
jq
并在
--arg
的过滤器语法中以各种方式插入参数来重写
jq
函数,但没有成功。

retrieve_from_array_v2(){
  local jq_result && \
  jq_result="$(jq -r --arg a "${1}" --arg k "${2}" --arg v "${3}" '.$a[] | select(.$k=="$v")' "./silly-sample.json")" && \
  echo "${jq_result}" && \
  return 0

  return 1
}

我收到一条

jq: error: syntax error, unexpected '$' (Unix shell quoting issues?) at <top-level>, line 1:
错误消息。

问题不在于替换我想要搜索的

=="Blackberry"
=="celery"
)。当我尝试用 `jq 中收到的参数替换 array (
.vegetables.with_a[]
,
.fruits_with_a[]
) 和 field (
.sku
,
.name
) 时,开始出现语法错误。

如何在不使用 eval 的情况下重写我的

bash
函数以使其工作?

bash filter dynamic syntax jq
1个回答
0
投票

我会使用

--arg
来获取参数,然后只需调用
jq
而不将其结果捕获到变量中:

retrieve_from_array2() {
  jq --arg cat "$1" --arg key "$2" --arg val "$3" \
    '.[$cat][] | select(.[$key] == $val)' ./silly-sample.json
}

retrieve_from_array2 "fruits_with_a" "fruitName" "Apricot"
{
  "fruitName": "Apricot",
  "value": "..."
}

由于对

jq
的调用是函数中的最后一个(也是唯一一个)调用,因此其退出代码会自动重新用作函数调用的退出代码。

© www.soinside.com 2019 - 2024. All rights reserved.