假设我有一个如下所示的JSON文件:
{
"name": "tom",
"scripts": {
"webpack": "webpack --progress --colors --watch"
},
"dependencies": {
},
"devDependencies": {
"webpack": "^2.2.1"
}
}
我希望能够按名称指定包,在dependencies
或devDependencies
中找到相应的条目并更新值。
我最接近的是:
$ jq --arg p webpack --arg v 1.2.3 'to_entries | map(
if (.value[$p]? | startswith("^")?) then
.value[$p] = $v
else .
end
) | from_entries' file.json
更新值但会删除dependencies
和name
属性:
{
"scripts": {
"webpack": "webpack --progress --colors --watch"
},
"devDependencies": {
"webpack": "1.2.3"
}
}
如何更新所需的值而不影响原始JSON中的其他属性?
答案 0 :(得分:1)
请改为尝试:
$ jq --arg p webpack --arg v 1.2.3 '
def update_package($package; $version):
if has($package) then .[$package] = $version
else . end;
.dependencies |= update_package($p; $v)
| .devDependencies |= update_package($p; $v)' project.json
update_package/2
只会在依赖对象实际引用给定项目时才更新它,否则它将保持不变。同时适用于dependencies
和devDependencies
。
原始过滤器删除dependencies
对象的问题在于,由于项目不存在,因此没有相应的更新值。通过对不存在的值应用startswith
,它会导致错误。该错误反过来被忽略并有效地跳过了地图中的相应项目,从而失去了该属性。
要快速修复以确保不会发生这种情况,请不要忽略该错误,在属性不存在时提供备用值。
.value[$p]? | startswith("^")? # bad
.value[$p] // "" | startswith("^") # better
答案 1 :(得分:1)
使用您的方法,最好使用map_values:
map_values(if type == "object"
then with_entries( if .key == $p and (.value | startswith("^")?)
then .value = $v else . end )
else . end)
您可能还想考虑使用walk/1
:
walk(if type == "object" and has($p) and (.[$p]|startswith("^"))
then .[$p] = $v else . end)
使用walk/1
的解决方案将递归检查JSON实体。如果您的jq没有walk
,则可以通过Google搜索轻松找到其在jq中的定义。
def when(p;q): if p//false then q else . end;
map_values( when(type == "object";
with_entries( when( .key == $p and (.value | startswith("^")?);
.value = $v) )) )