我正在尝试将shell脚本中的JSON对象解析为数组。
例如:[Amanda,25岁,http://mywebsite.com]
JSON看起来像:
{
"name" : "Amanda",
"age" : "25",
"websiteurl" : "http://mywebsite.com"
}
我不想使用任何库,最好是我可以使用正则表达式或grep。我做了:
myfile.json | grep name
这给了我“名字”:“阿曼达”。我可以在文件中的每一行循环中执行此操作,并将其添加到数组中,但我只需要右侧而不是整行。
答案 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"
。在这种情况下,Amanda
和lastname
都将被读入每个单独的数组字段。为避免这种情况,您可以使用readarray
,例如
readarray -t array < <(sed -n '/{/,/}/{s/[^:]*:[^"]*"\([^"]*\).*/\1/p;}' json2)
这也将处理评论中也提到的任何通配问题。