在shell脚本中解析json数组

5
我需要从一个JSON字符串中打印键和值。我已经解析了一个简单的JSON字符串。
            {
              "Name": "test1",
              "CreateDate": "2016-08-30T10:52:52Z",
              "Id": "testId1",
            }

我的代码是这样的。
 q1=$(echo $x | grep -Po '"Name":.*?[^\\]",'| perl -pe 's/"Name": //; s/^"//; s/",$//');

 q2=$(echo $x | grep -Po '"Id":.*?[^\\]",'| perl -pe 's/"Id": //; s/^"//; s/",$//');

    echo $q1 "," $q2;

但是这段代码并不适用于像这样的json字符串。
x='{    "TestNames":
        [{
        "Name": "test1",
        "CreateDate": "2016-08-30T10:52:52Z",
        "Id": "testId1"
         }, 
         {
        "Name":  "test2",
        "CreateDate": "2016-08-30T10:52:13Z",
        "Id": "testId2"
    }]
}';

我需要这样打印。
test1 , testId1
test2 , testId2

使用grep命令可以获取这样的数据吗?

数据不是有效的 JSON 格式。JSON 解析器会报告:解析错误:在第 6 行,第 10 列期望另一个键值对(如果其后紧接着另一个键值对,则允许在键值对之后添加命令)。 - hek2mgl
既然每个人都建议您安装第三方程序...如果您的 JSON 格式没有更改,您的键数量有限,并且您需要一个纯 Bash+grep解决方案,您可以分别在两个 Bash 数组中 grep 名称和 ID,然后并排打印它们 - makadev
如果你的“JSON”格式不变,键值有限,并且需要一个纯Bash+grep解决方案……那么你正在做一些错误的事情。 - hek2mgl
如果您的应用程序需要处理JSON,而您的服务器上没有任何可以解析JSON的工具,且您无法安装任何工具,则您的做法是错误的。 - hek2mgl
@makadev,grep解决方案无法处理JSON字符串中的\n序列、\t\",而确保您的代码在内容更改时立即崩溃会使整个解决方案变得不必要地脆弱。我曾经有客户构建了非常脆弱的代码,甚至无法处理JSON字典中不同的键顺序——一旦我们升级了序列化库(更不用说扩展API),这意味着这些客户已经自毁了。引导人们走上这条路是非常不明智的。 - Charles Duffy
显示剩余3条评论
2个回答

11

首先,你的数据不是有效的JSON,有一个多余的逗号:

{
  "TestNames": [
    {
      "Name": "test1",
      "CreateDate": "2016-08-30T10:52:52Z",
      "Id": "testId1", <--- Remove that!
    },
    {
      "Name": "test2",
      "CreateDate": "2016-08-30T10:52:13Z",
      "Id": "testId2"
    }
  ]
}

一旦你修复了这个问题,就可以使用jq在命令行上解析json:

echo "$x" | jq -r '.TestNames[]|"\(.Name) , \(.Id)"'

如果您需要保留输出值。

declare -A map1

while read name id ; do
    echo "$name"
    echo "$id"
    map1[$name]=$id

done < <(echo "$x" | jq -r '.TestNames[]|"\(.Name) \(.Id)"')

echo "count : ${#map1[@]}"
echo "in loop: ${map1[$name]}"

使用这种方法,是否可以将结果分别添加到变量中?(例如:print1 = echo“$ x”| jq -r '.TestNames [] |“\(.Name),\(.Id)”'; echo $ print1;) - Abdul Manaf
你正在寻找命令替换吗? - hek2mgl
我会使用while循环,像这样:http://pastebin.com/SEh22pAH - hek2mgl
1
谢谢hek2mgl,它对我有用。我一直在寻找这样的解决方案。 - Abdul Manaf
为什么 jq -r '.TestNames[]|"\(.Name) \(.Id)"' 可以工作,但 jq -r ".TestNames[]|'\(.Name) \(.Id)'" 不行? - wsdzbm
显示剩余4条评论

2
我建议使用命令行JSON解析器jq
$ echo '''{
          "Name": "test1",
          "CreateDate": "2016-08-30T10:52:52Z",
          "Id": "testId1"
        }''' | jq  '.Name + " , " + .Id'

"test1 , testId1"


$ echo '''{    "TestNames":
    [{
    "Name": "test1",
    "CreateDate": "2016-08-30T10:52:52Z",
    "Id": "testId1"
     },
     {
    "Name":  "test2",
    "CreateDate": "2016-08-30T10:52:13Z",
    "Id": "testId2"
}]
}''' | jq '.TestNames[] | .Name + " , " + .Id'

"test1 , testId1"
"test2 , testId2"

.TestNames | .[] 应该简化为 TestNames[] - hek2mgl
谢谢,我一开始尝试使用.TestNames.[],发现它不起作用,觉得很奇怪。 - Aaron
小心!使用.TestNames[],而不是.TestNames.[] - hek2mgl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接