将JSON解析为shell脚本中的数组

时间:2016-07-14 01:45:36

标签: json bash shell parsing

我正在尝试将shell脚本中的JSON对象解析为数组。

例如:[Amanda,25岁,http://mywebsite.com]

JSON看起来像:

{
  "name"       : "Amanda", 
  "age"        : "25",
  "websiteurl" : "http://mywebsite.com"
}

我不想使用任何库,最好是我可以使用正则表达式或grep。我做了:

myfile.json | grep name

这给了我“名字”:“阿曼达”。我可以在文件中的每一行循环中执行此操作,并将其添加到数组中,但我只需要右侧而不是整行。

3 个答案:

答案 0 :(得分:17)

如果你真的不能使用适当的JSON解析器,例如jq [1] ,尝试基于 awk的解决方案

Bash 4.x:

readarray -t values < <(awk -F\" 'NF>=3 {print $4}' myfile.json)

Bash 3.x:

IFS=$'\n' read -d '' -ra values < <(awk -F\" 'NF>=3 {print $4}' myfile.json)

这会将所有属性存储在Bash数组${values[@]}中,您可以通过它检查 declare -p values

这些解决方案有局限性:

  • 每个属性必须独立,
  • 所有值必须加双引号,
  • 不支持嵌入式转义双引号。

所有这些限制都强化了使用正确的JSON解析器的建议。

注意:以下替代解决方案使用Bash 4.x + readarray -t values命令,但它们也适用于Bash 3.x替代方案IFS=$'\n' read -d '' -ra values

grep + cut组合:单个grep命令不会做(除非您使用 GNU { {1}} - 见下文),但添加grep会有所帮助:

cut

GNU readarray -t values < <(grep '"' myfile.json | cut -d '"' -f4) :使用grep支持PCRE,支持-P删除到目前为止匹配的所有内容(更多灵活替代后面的断言)以及前瞻断言(\K):

(?=...)

最后,这里有一个纯Bash(3.x +)解决方案

在性能方面,这是一个可行的替代方案是在每个循环迭代中都没有调用外部实用程序;但是,对于较大的输入文件,基于外部实用程序的解决方案会更快。

readarray -t values < <(grep -Po ':\s*"\K.+(?="\s*,?\s*$)' myfile.json)

[1]这里的基于#!/usr/bin/env bash declare -a values # declare the array # Read each line and use regex parsing (with Bash's `=~` operator) # to extract the value. while read -r line; do # Extract the value from between the double quotes # and add it to the array. [[ $line =~ :[[:blank:]]+\"(.*)\" ]] && values+=( "${BASH_REMATCH[1]}" ) done < myfile.json declare -p values # print the array 的强大解决方案看起来像什么(Bash 4.x):
jq

答案 1 :(得分:3)

jq足以解决这个问题

paste -s <(jq '.files[].name' YourJsonString) <(jq '.files[].age' YourJsonString) <( jq '.files[].websiteurl' YourJsonString) 

这样你就可以获得一个表,你可以grep任何行或awk打印你想要的任何列

答案 2 :(得分:1)

您可以使用sed one liner实现此目的:

array=( $(sed -n "/{/,/}/{s/[^:]*:[[:blank:]]*//p;}" json ) )

结果:

$ echo ${array[@]}
"Amanda" "25" "http://mywebsite.com"

如果您不需要/想要引号,那么以下sed将取消它们:

array=( $(sed -n '/{/,/}/{s/[^:]*:[^"]*"\([^"]*\).*/\1/p;}' json) )

结果:

$ echo ${array[@]}
Amanda 25 http://mywebsite.com

如果您有多个条目,例如

,它也会有效
$ cat json
{
  "name"       : "Amanda" 
  "age"        : "25"
  "websiteurl" : "http://mywebsite.com"
}

{
   "name"       : "samantha"
   "age"        : "31"
   "websiteurl" : "http://anotherwebsite.org"
}

$ echo ${array[@]}
Amanda 25 http://mywebsite.com samantha 31 http://anotherwebsite.org

更新:

正如评论中的mklement0所指出的,如果文件包含嵌入的空格,可能会出现问题,例如"name" : "Amanda lastname"。在这种情况下,Amandalastname都将被读入每个单独的数组字段。为避免这种情况,您可以使用readarray,例如

readarray -t array < <(sed -n '/{/,/}/{s/[^:]*:[^"]*"\([^"]*\).*/\1/p;}' json2)

这也将处理评论中也提到的任何通配问题。