如何在Bash函数中不使用Eval实现jq过滤器参数化?
不用Eval实现Bash中jq动态路径与字段的数组搜索函数
你需要在Bash脚本中通过jq搜索JSON文件任意位置的数组元素,原实现采用字符串拼接+eval执行命令的方式,属于不良实践,不利于扩展多条件搜索。尝试用--arg传递参数时出现语法错误,核心问题是动态路径(如.vegetables.with_a)和字段名(如.n)不能直接用--arg传递的字符串当作jq的标识符使用。
错误原因分析
你编写的retrieve_from_array_v2函数中,.$a[] | select(.$k=="$v")是错误语法:
$a是--arg传递的字符串变量,jq不会自动将其解析为路径(比如.vegetables.with_a),直接写.$a会触发语法错误。- 字段名
$k同理,不能直接写成.$k,需要用索引语法.[$k]来访问动态字段。
正确实现方式
方法1:用getpath解析动态路径
getpath可以将字符串数组形式的路径解析为jq的实际路径,需先把点分隔的路径(如vegetables.with_a)拆分成数组(如["vegetables", "with_a"])。
retrieve_from_array_v2(){ local jq_result jq_result="$(jq -r --arg path_str "$1" --arg field "$2" --arg value "$3" ' # 将点分隔的路径字符串转为数组 $path_str | split(".") as $path # 按路径获取数组,遍历元素并筛选 | getpath($path)[] | select(.[$field] == $value) ' "./silly-sample.json")" echo "${jq_result}" return 0 }
方法2:用jq内置eval解析路径字符串
如果路径格式固定符合jq语法(比如.vegetables.with_a),可以用jq内置的eval函数(注意这是jq的安全内置函数,和shell的eval完全不同)解析路径字符串。
retrieve_from_array_v2(){ local jq_result jq_result="$(jq -r --arg path_expr "$1" --arg field "$2" --arg value "$3" ' # 解析路径表达式,获取目标数组 eval($path_expr)[] # 用索引语法访问动态字段,筛选匹配值 | select(.[$field] == $value) ' "./silly-sample.json")" echo "${jq_result}" return 0 }
注:若要保留原调用参数格式(路径带开头的点,如
.vegetables.with_a),直接传递该参数即可;若参数不带开头的点,可修改为eval("." + $path_expr)[]。
测试示例
调用方法1的函数(参数格式和原函数一致):
retrieve_from_array_v2 "fruits_with_a" "fruitName" "Apricot" && echo "Executed successfully!!!" retrieve_from_array_v2 "vegetables.with_a" "n" "asparagus" && echo "Executed successfully!!!"
多条件搜索扩展
若要支持多条件搜索,只需在select中添加更多判断逻辑,通过--arg传递额外的字段和值参数即可:
retrieve_with_multi_conditions(){ local jq_result jq_result="$(jq -r --arg path_str "$1" --arg field1 "$2" --arg val1 "$3" --arg field2 "$4" --arg val2 "$5" ' $path_str | split(".") as $path | getpath($path)[] | select(.[$field1] == $val1 and .[$field2] == $val2) ' "./silly-sample.json")" echo "${jq_result}" }
内容的提问来源于stack exchange,提问作者Bianca Luxambio
相关产品推荐
相关产品推荐

