Jq

是否可以使用 with_entries 方法用 jq 遞歸更改鍵名?

  • June 22, 2021

假設我有以下 JSON 文件:

[
 {
   "name1": "fruits",
   "name2": "cars",
   "name3": "houses"
 }
]

我知道我可以jq用來重命名它的值,如下所示:

jq '[.[] | .["newname1"] = .name1 | del(.name1)]' file

這工作得很好,它允許我甚至對更複雜的 JSON 結構進行更改……但是,這是我想要更改的鍵的非常明確的聲明。做同樣事情的另一種方法是使用命令:

jq 'map(with_entries(if .key == "name1" then .key = "newname1" else . end))' file 

這是一種檢查作為對像數組的 JSON 中具有特定名稱的所有鍵並更改它們的方法。key在這種情況下,我不需要明確聲明的名稱。但是,這僅適用於對像數組。我想找到一種以遞歸方式更改 json 中所有鍵的方法。假設我有一個像下面這樣的 JSON:

{
 "name1": "one",
 "type": "FeatureCollection",
 "features": [
   {
     "name1": "one",
     "valueA": "0",
     "valueB": "0",
     "keyB": "2",
     "keyC": "3"
   },
   {
     "name1": "two",
     "valueA": "11",
     "valueB": "21",
     "keyB": "15",
     "keyC": "20"
   }
 ]
}

我的最後一個jq命令不適用於這個 JSON。有沒有辦法name1使用遞歸更改所有鍵jq?也許找到一種recurse(.[]?;true)與此命令一起使用的方法?可能嗎?

jq 'walk(if type == "object" then with_entries( if .key == "name1" then .key = "newname1" else . end ) else . end)' file

這或多或少直接來自jq手冊(描述walk()功能的部分)。該walk()函式的作用類似於“遞歸map()”,我們唯一需要注意的是檢查我們目前正在處理的實體的類型。

使用walk(),您也可以應用您的第一種方法:

jq 'walk(if type == "object" and has("name1") then ( .newname1 = .name1 | del(.name1) ) else . end)' file

但是,這確實將newname1密鑰放在每個對象的最後,而不是name1在找到它的位置替換(如果重要的話)。

另一種方法(jq1.6)是使用遞歸體面操作符..,選擇任何具有我們正在尋找的鍵的東西,然後更新這些對象:

jq '(.. | select(has("name1")?)) |= with_entries(if .key == "name1" then .key = "newname1" else . end)' file

引用自:https://unix.stackexchange.com/questions/655253