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

vsmadaxz  于 2023-04-21  发布在  Shell
关注(0)|答案(4)|浏览(276)

我正在尝试将shell脚本中的JSON对象解析为数组。
例如:阿曼达,25,[http://mywebsite.com]
JSON看起来像:

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

我不想使用任何库,最好使用正则表达式或grep。我已经完成了:

myfile.json | grep name

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

nnt7mjpx

nnt7mjpx1#

如果您确实无法使用jq [1]等合适的JSON解析器,请尝试**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命令不行(除非你使用 GNUgrep-见下文),但是添加cut会有帮助:

readarray -t values < <(grep '"' myfile.json | cut -d '"' -f4)

GNUgrep:使用-P来支持PCRE,PCRE支持\K删除到目前为止匹配的所有内容(一种比后看Assert更灵活的替代方法)以及前看Assert((?=...)):

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

最后,这里是一个纯Bash(3.x+)解决方案
在性能方面,这是一个可行的替代方案,因为 * 在每次循环迭代中都不会调用外部实用程序 *;但是,对于较大的输入文件,基于外部实用程序的解决方案会快得多。

#!/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

[1]下面是基于jq的健壮解决方案的样子(Bash 4.x):
readarray -t values < <(jq -r '.[]' myfile.json)

nhhxz33t

nhhxz33t2#

jq足够好来解决这个问题

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

这样你就得到了一个表,你可以grep任何行或者awk打印任何列

bnlyeluc

bnlyeluc3#

您可以使用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

更新:
正如mklement 0在注解中指出的那样,如果文件包含嵌入的空格,例如"name" : "Amanda lastname",则可能会出现问题。在这种情况下,Amandalastname都将被读入单独的数组字段。为了避免这种情况,您可以使用readarray,例如,

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

这也将照顾到任何globbing问题,也在评论中提到。

kd3sttzy

kd3sttzy4#

纯Bash 3.x+,无依赖项(如jq、python、grep等):

source <(curl -s -L -o- https://github.com/lirik90/bashJsonParser/raw/master/jsonParser.sh)
read -d '' JSON << EOF
{
  "name"       : "Amanda", 
  "age"        : "25",
  "websiteurl" : "http://mywebsite.com"
}
EOF

JSON=$(minifyJson "$JSON")
name=$(parseJson "$JSON" name)
age=$(parseJson "$JSON" age)
url=$(parseJson "$JSON" websiteurl)
echo "Result: [$name,$age,$url]"

输出:

Result: [Amanda,25,http://mywebsite.com]

Try it

相关问题