我想创建一个类似jq
的小函数,它执行get-or-default-if-not-present,类似于Python的dict.get(key, default)
,这是我们想要的行为:
% echo '{"nested": {"key": "value", "tricky": null}}' > file.json
% my-jq nested.key \"default\" file.json
"value"
% my-jq nested.tricky \"default\" file.json
null
% my-jq nested.dne \"default\" file.json
"default"
我试过使用this answer to a similar question,但是它对嵌套键不起作用。有人有什么建议吗?
function my-jq () {
jq --arg key "$1" --arg default "$2" \
'if has($key) then .[$key] else $default | fromjson end' "$3"
}
3条答案
按热度按时间7y4bm7vi1#
基于你对"类jq"函数的预测,可以合理地假设你的参数不仅应该被看作路径表达式,而且应该被看作一个通用的jq过滤器,也就是代码,在当前版本的jq中,没有选项或其他速记方法可以像
--arg
和--argjson
对数据那样对代码有效。然而,您可以通过jq的库/模块系统导入代码片段,但对于手头的任务,您需要将代码从函数的参数存储到(临时)文件,在实际jq过滤器的静态部分引用它,之后删除该文件,这不仅繁琐,而且在模块文件中也需要一些静态开销,这不可避免地打开了标注为"代码注入"的潘多拉盒子,因此您也可以屈服于释放出来的邪恶,并使用以下文字动态地组成实际的jq过滤器(并且可能是恶意的)参数内容。(注意,这假设jq表达式有效,因此使用前面带点的
.nested.key
等):这种最小化方法使用了替代运算符
//
,它不能给出一个真实但错误的值("null"或"false"),除了空流之外(缺失值)。为了抵消这一点,您可以在基本文档的所有paths
中检查path
输入是否存在,这将极大地减少您的函数所接受的过滤器种类(考虑到您的用例,这甚至可能被认为是一件好事,但恶意注入仍然是可能的),并且与所有路径进行比较可能会对具有复杂结构的基本文档带来性能损失,但它满足您的三个测试用例:一个二个一个一个
最后,通过组合两种方法可以减轻潜在的性能损失,即对于一般情况以较快的第一种方法开始,但是如果第一种方法产生不明确的错误值,则返回到可能较慢的第二种方法:
nbewdwxp2#
你不能使用点线路径作为键序列。但是你可以将这样的路径转换成有效的路径以供
getpath
函数使用。(可能有一个更干净、更健壮的方法来实现这一点。)//
运算符提供了一个替代值,如果左边产生false
或null
。$key | ltrimstr(".") | split(".")
首先去掉前面的.
,然后在剩余的.
上拆分剩余的字符串,以产生单独的键的列表。getpath
使用该键的列表产生过滤器;getpath(["nested", "key"])
等效于(AFAIK).nested.key
。mftmpeh83#
您的需求有点违背JSON的规则,但这里有一个可能的解决方案,或者说是一系列解决方案的基础。
此特定解决方案假定路径以数组形式给出:
示例: