Jq
如何使用jq搜尋和替換數組中的多個值?
在以下 json 文件中,
{ "contacts": [ { "name": "John", "phone": "1234" }, { "name": "Jane", "phone": "5678" } ] }
我需要根據名稱更新兩個電話號碼並將整個 json 儲存在一個新文件中。
我嘗試過類似的東西:
jq '.contacts[] | select(.name == "John") | .phone = "4321"' < contacts.json >updated_contacts.json
但是後來我不知道如何回到父節點並更改簡的那個,也不知道如何檢索整個 json。
我試圖將根節點儲存在一個變數中
as
,但它保持不變。作為臨時解決方法,我只是這樣做:
jq '.contacts[0].number = "4321" | .contacts[1].number = "4321"' < contacts.json >updated_contacts.json
但我不應該依賴數組索引,而是名稱,因為原始 json 可能會改變。
知道如何使用 jq 命令來做到這一點嗎?
要更改一個條目,請確保您使用
|=
並且該更新運算符的左側是原始文件中的路徑:jq --arg name John --arg phone 4321 \ '( .contacts[] | select(.name == $name) ).phone |= $phone' file
您不能使用
.contacts[] | select(.name == "John") | .phone |= ...
,因為實際上從數組select()
中提取了一組元素。contacts
因此,您將只更改您提取的元素,與文件的主要部分分開。注意區別
( ... | select(...) ).phone |= ... ^^^^^^^^^^^^^^^^^^^^^ path in original document
哪個有效,並且
... | select(...) | .phone |= ... ^^^^^^^^^^^ extracted bits
這是行不通的。
對多個條目使用循環,假設例如
bash
:names=( John Jane ) phones=( 4321 4321 ) tmpfile=$(mktemp) for i in "${!names[@]}"; do name=${names[i]} phone=${phones[i]} jq --arg name "$name" --arg phone "$phone" \ '( .contacts[] | select(.name == $name) ).phone |= $phone' file >"$tmpfile" mv -- "$tmpfile" file done
也就是說,我將名稱放在一個數組中,將新數字放在另一個數組中,然後循環索引並更新
file
每個需要更改的條目,使用臨時文件作為中間儲存。或者,使用關聯數組:
declare -A lookup lookup=( [John]=4321 [Jane]=4321 ) for name in "${!lookup[@]}"; do phone=${lookup[$name]} # jq as above done
假設您有一些帶有新電話號碼的 JSON 輸入文件,例如
{ "John": 1234, "Jane": 5678 }
您可以使用創建
jo John=1234 Jane=5678
然後您可以在一次
jq
呼叫中更新數字:jo John=1234 Jane=5678 | jq --slurpfile new /dev/stdin \ '.contacts |= map(.phone = ($new[][.name] // .phone))' file
這會使用結構中的新數字讀取我們的輸入 JSON
$new
,看起來像[ { "John": 1234, "Jane": 5678 } ]
這在
map()
呼叫中用於更改列出的任何联係人的電話號碼。// .phone
確保如果未列出姓名,則電話號碼保持不變。