我是 JQ 庫的新手,我無法弄清楚如何用 config.json 和 config_new.json 中存在的鍵值遞回地替換 config_new.json 中的值,而無需從 config.json 復制任何其他屬性。
基本上有:
// config_new.json
{
"name": "testName",
"age": "tooOld",
"properties": {
"title": "Mr",
"fruits": ["apple", "banana"]
},
}
// config.json
{
"newName": "changedName",
"age": "tooYoung",
"properties": {
"title": "Mr",
"height": "tooTall",
"fruits": ["banana"]
},
"certificate": "present"
}
// expected result
{
"name": "testName",
"age": "tooYoung",
"properties": {
"title": "Mr",
"height": "tooTall",
"fruits": ["banana"]
},
}
所以我試圖僅用 config.json 中的已知值覆寫 config_new.json 中的值。
我試過使用
jq -s '.[0] * .[1]' config_new.json config.json
但這僅部分有效,因為它還復制了 config_new.json 中不存在的鍵值對:
{
"name": "testName",
"newName": "changedName", // This should not be here
"age": "tooYoung", // This was replaced from config.json
"properties": {
"title": "Mr",
"height": "tooTall", // This should not be here
"fruits": ["banana"]
},
}
有人可以幫助我嗎?
uj5u.com熱心網友回復:
我想提出一些建議,但我不確定它是否適合您的要求:不要合并 JSON 檔案,而是將您的“目標”檔案撰寫為 jq 程式本身。
config_new.jq:
{
"name": .name,
"age": .age,
"properties": {
"title": .properties.title,
"fruits": .properties.fruits
}
}
這讀起來幾乎就像“真正的”JSON。
或者,如果您想減少重復:
{
name,
age,
properties: .properties | {
title,
fruits
}
}
然后將舊檔案遷移到新格式:
jq -f config_new.jq config.json > config_new.json
“從不同檔案的相同鍵復制值”方法會更復雜,但讓我們等待其他答案。我很確定有辦法,但我太笨了:) 它可能在某種程度上涉及reduce和path// getpath。setpath
uj5u.com熱心網友回復:
這是一個 jq 答案,它根據您的標準遞回地合并物件:
jq -s '
def merge($source):
. as $target
| reduce ($source | keys | map(select(in($target))))[] as $key ($target;
.[$key] = if (.[$key] | type) == "object"
then .[$key] | merge($source[$key])
else $source[$key]
end
)
;
. as [$new, $old]
| $new | merge($old)
' config_new.json config.json
輸出
{
"name": "testName",
"age": "tooYoung",
"properties": {
"title": "Mr",
"fruits": [
"banana"
]
}
}
這將 config_new.json 作為“目標”,將 config.json 作為“源”。要將 $source 合并到 $target 中,遍歷 $target 中的 $source 鍵,然后查看鍵值的資料型別:如果它是物件,則遞回合并這些物件,否則將 $source 的值放入 $target為那把鑰匙。
uj5u.com熱心網友回復:
好吧,這是我認為可能的解決方案。如果有改進的余地,請發表評論。
$ jq --slurpfile cfg config.json '. as $new
| reduce (paths(scalars,arrays) | select(any(numbers)|not)) as $path (
{};
setpath($path; ($cfg[0]|getpath($path))//($new|getpath($path))))' config_new.json
{
"name": "testName",
"age": "tooYoung",
"properties": {
"title": "Mr",
"fruits": [
"banana"
]
}
}
它通過迭代所有不包含陣列的路徑來減少。分解:
. as $new # store original "new" json
| reduce (paths(scalars,arrays) | select(any(numbers)|not)) as $path ( # reduce over all paths of input (original "new" json) that are leaf paths or arrays (but not array elements)!
{}; # start with an empty result
setpath(
$path; # set "$path" in the result
($cfg[0]|getpath($path)) # query value from existing config (read via slurpfile)
// ($new|getpath($path)))) # if value does not exist or is null, use existing value (from original "new" json)
請注意,“null”或“false”中config.json的值不會覆寫 中的現有值config_new.json。要處理null和false,您需要更聰明:
. as $new
| [$cfg[0] | paths] as $cfg_paths # store all paths from config.json
| reduce (paths(scalars,arrays) | select(any(numbers)|not)) as $path (
{};
setpath(
$path;
if $path|IN($cfg_paths[]) # check if $path exists in config
then $cfg[0] else $new # use old or new config
end | getpath($path) # get $path from old/new config respectively
)
)
finalif也可以select用過濾器表示:
. as $new
| [$cfg[0] | paths] as $cfg_paths
| reduce (paths(scalars,arrays) | select(any(numbers)|not)) as $path (
{};
setpath(
$path;
$cfg[0] | select($path|IN($cfg_paths[])) // $new # $cfg if path exists, otherwise $new (equivalent to "if" above)
| getpath($path)
)
)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/519943.html
