2017-07-08 44 views
3

我有一個JSON響應如下所示:提取JSON值殼可變使用JQ

[ 
{"id":10, 
"list_file":["/var/a.txt", 
      "/dev/b.txt"]} 
] 

我需要提取list_file的值,並存儲它外殼變量爲一個數組。我試着循環閱讀值。

#!/bin/bash 
x=() 
while read -r value 
do 
    #echo "$value" 
    x+=("$value") 
done < <(jq -r '.[] | .list_file' input.json) 

但是數組中提取的值也包含引號,括號和逗號。

[ 
    "/var/a.txt", 
    "/dev/b.txt" 
] 

能否請你幫我修改代碼,使陣列只包含的條目/var/a.txt和/dev/b.txt。此外,我嘗試了readarray和地圖,但他們不會在Mac Osx上工作。任何幫助將非常感激。

+0

這不是有效的JSON,請你解決你的榜樣(通過[編輯](https://stackoverflow.com/posts/44981265/edit)的問題) –

+0

更正了json。 – tom

回答

3

爲了妥善處理所有的值,你需要使用declare命令的jq輸出納入數組賦值。

下面是一些需要擔心的角落案例的輸入:空格,換行符和glob字符。

$ cat input.json 
[ 
    {"id":10, 
    "list_file":[ 
     "/var/a b.txt", 
     "/dev/c\nd.txt", 
     "*"]} 
] 

一個jq命令提取並通過外殼輸出正確引用使用字符串:

$ $ jq -r '.[] | .list_file[] | @sh' input.json 
'/var/a b.txt' 
'/dev/c 
d.txt' 
'*' 

和外殼命令可以使用輸出:

$ declare -a "x=($(jq -r '.[] | .list_file[] | @sh' input.json))" 

證明它工作正常:

$ printf '==%s==\n' "${x[@]}" 
==/var/a b.txt== 
==/dev/c 
d.txt== 
==*== 
+0

謝謝你!這個答案很好,微妙和棘手的谷歌。 – xer0x

3

可以在組合使用@tsv串格式化器與--raw-output/-r選項和輸出拆分bash陣列上選項卡:用於製造jq濾波器交談非

$ IFS=$'\t' 
$ x=($(jq -r '.[] | .list_file | @tsv' input.json)) 
$ for xx in "${x[@]}"; do echo "$xx"; done 
/var/a.txt 
/dev/b.txt 

對於-r將剝離外部引號(有用基於JSON的系統),並且@tsv將輸出一個數組作爲一系列製表符分隔的字符串(製表符,換行符等將被轉義)。

或者,您可以使用@sh過濾器,該過濾器將數組作爲一系列空格分隔的字符串輸出。然而,爲了解釋這些輸出,你必須eval審視你們吧:

$ eval "x=($(jq -r '.[] | .list_file | @sh' input.json))" 
+0

請你讓我知道如何擺脫引號,因爲我將不得不循環指定的路徑和處理文件。 – tom

+0

非常感謝:) – tom

+2

這不完全正確。輸出被引用,但shell本身不會將引號視爲在此上下文中的語法引號;嘗試使用包含空格的'list_file'中的文件名。 – chepner

0
  1. 在Mac上,安裝帶有readarray(例如,使用自制軟件:brew install bash),所以在下面我會假設它是可用的,但您也可以使用while read -r value技術逐行讀取值。 (這些面向行的方法的一個優點是不需要撥動IFS。)

  2. 對於手頭的問題,可能會出現這樣的情況,最好是保留特殊字符的JSON表示,例如NEWLINE的「\ n」,NUL的「\ u0000」等。無論如何,使用-r一個通用的方法是使用-c命令行選項來代替,如下圖所示:

$ readarray -t x < <(jq -n -c '("\u0001\nb", "c\td", "e\u0000f")' 
    | sed -e 's/^\"//' -e 's/\"$//') 
$ printf ":%s:\n" "${x[@]}" 
:\u0001\nb: 
:c\td: 
:e\u0000f: