使用jq将JSON值提取到shell变量

时间:2017-07-08 00:14:57

标签: json bash shell jq

我有一个json响应,如下所示:

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

我需要提取list_file的值并将其作为数组存储在shell变量中。我尝试循环并读取值。

#!/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和map,但它们无法在Mac Osx上运行。任何帮助都会非常感激。

3 个答案:

答案 0 :(得分:3)

您可以将@tsv字符串格式化程序与--raw-output/-r选项结合使用,并将输出拆分为选项卡上的bash数组:

$ 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,将删除外部引号(对于使jq过滤器与非基于JSON的系统进行对话非常有用),@tsv将输出一个数组作为一系列标签 - 分隔的字符串(标签,换行符等将被转义)。

或者,您使用@sh过滤器将数组输出为一系列以空格分隔的字符串。但是,要解释此类输出,您必须eval使用它:

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

答案 1 :(得分:3)

为了正确处理所有值,您需要使用declare命令将jq的输出合并到数组赋值中。

这里有一些输入,需要担心一些角落情况:空格,换行符和全局字符。

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

jq命令,用于提取和输出正确引用的字符串以供shell使用:

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

可以使用输出的shell命令:

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

证明它运作正常:

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

答案 2 :(得分:0)

  1. 在Mac上,安装带有readarray的bash很容易(例如使用自制软件:brew install bash),所以在下面我会假设它和&#39; ll #39;可用,但您也可以使用while read -r value技术逐行读取值。 (这些面向行的方法的一个优点是不需要使用IFS。)

  2. 对于手头的问题,可能会出现这样的情况:保留特殊字符的JSON表示形式会更好,例如&#34; \ n&#34;对于NEWLINE,&#34; \ u0000&#34;对于NUL等,无论如何,使用-r的一般替代方法是使用-c命令行选项,如下所示:

  3. $ 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: