2017-06-13 57 views
2

我有以下簡單的JSON如何修剪JQ中每個元素的空白?

json='[{"k1":" http://url", "k2":null, "k3":" v3", "k4":" v4"}]' 

我需要的是:

"http://url",null 

(不v1之前和空間v2

我所擁有的是:

echo $json | jq -c '.[] | .k1, .k2 ' | paste -d "," - - 

如何擺脫k1中的空間和k2值?

+1

你有足夠的一個JQ新有'walk'功能? –

+1

順便說一句,'echo $ json'實際上是有點bug的 - 如果你的文本中有一個空格包圍的'*',它將被替換爲一個文件名列表。 'echo'$ json「'更好。 –

+0

@CharlesDuffy我有最新的'jq'版本。 –

回答

2

的下面將刪除開頭和結尾中的字符串空格的任意複雜的JSON結構內的任何地方:

#!/usr/bin/env jq -cf 

# Define walk function (standard library only for jq 1.6 and newer, currently unreleased) 
def walk(f): 
    . as $in 
    | if type == "object" then 
     reduce keys_unsorted[] as $key 
     ({}; . + { ($key): ($in[$key] | walk(f)) }) | f 
    elif type == "array" then map(walk(f)) | f 
    else f 
    end; 

walk(
    if type == "string" then 
    (sub("^[[:space:]]+"; "") | sub("[[:space:]]+$"; "")) 
    else . end 
) 

如果一個保存上述(例如,在trim-json),並將其標記爲可執行(chmod +x trim-json),然後./trim-json <<<"$json"與給定的輸入發出:

[{"k1":"v1","k2":"v2","k3":"v3","k4":"v4"}] 

同樣,用更新的輸入:

$ json='[{"k1":" http://url", "k2":null, "k3":" v3", "k4":" v4"}]' 
$ ./trim-json <<<"$json" 
[{"k1":"http://url","k2":null,"k3":"v3","k4":"v4"}] 
+0

你的解決方案效果很好,但有一個新的要求我忘了提及 - 它必須能夠使用null或空字符串''''或使用url。我已經更新了這個問題。 –

+0

這段代碼*不*已經在這些情況下工作了嗎? –

+0

@AdamSiemion,...我用已更新的輸入運行現有的代碼。如編輯中所示,它完美運行。 (鑑於此,我很好奇你爲什麼回到我身邊並要求更改)。 –

0

你的例子是常規的,因爲每個值都以不需要的空間開始。如果這是真正的代表性,那麼一個簡單的地圖上的範圍切片工作:

$ jq -c '.[] | map_values(.[1:]) | .k1,.k2' <<< "$json" | paste -d "," - - 
"http://url",null 

這種方法的是謙遜和簡單易懂的好處。如果你的例子不符合現實 - 零個或多個空格,嵌套數組等 - 那麼你需要使用gsub,條件等來部署更全面的方法。

+1

這會去掉第一個字符,不管它是什麼。如果不確定*每個*字符串都有前導空間,那麼......有點危險。 –

3

如果輸入的是JSON對象的數組,如果你正在尋找一個班輪,那麼下面似乎滿足您的要求:

jq '.[]|(.k1,.k2)|if type=="string" then gsub("^\\s+|\\s+$";"") else . end' | paste -d "," - - 

隨着你的輸入,這將產生

"http://url",null 

如果您對輸出中的null如何靈活處理,您可能還會考慮採用全jq解決方案(即不含paste)。例如:

jq -r '.[]|[.k1,.k2]|map(if type=="string" then gsub("^\\s+|\\s+$";"") else . end)|@csv' 

隨着你的輸入,這將產生:

"http://url",