我在
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
函数以使其工作?
我会使用
--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
的调用是函数中的最后一个(也是唯一一个)调用,因此其退出代码会自动重新用作函数调用的退出代码。