在shell脚本中读取json数据

时间:2013-12-10 07:14:57

标签: json bash shell

在shell中我有一个要求,其中我必须阅读以下格式的JSON响应:

 { "Messages": [ { "Body": "172.16.1.42|/home/480/1234/5-12-2013/1234.toSort", "ReceiptHandle": "uUk89DYFzt1VAHtMW2iz0VSiDcGHY+H6WtTgcTSgBiFbpFUg5lythf+wQdWluzCoBziie8BiS2GFQVoRjQQfOx3R5jUASxDz7SmoCI5bNPJkWqU8ola+OYBIYNuCP1fYweKl1BOFUF+o2g7xLSIEkrdvLDAhYvHzfPb4QNgOSuN1JGG1GcZehvW3Q/9jq3vjYVIFz3Ho7blCUuWYhGFrpsBn5HWoRYE5VF5Bxc/zO6dPT0n4wRAd3hUEqF3WWeTMlWyTJp1KoMyX7Z8IXH4hKURGjdBQ0PwlSDF2cBYkBUA=", "MD5OfBody": "53e90dc3fa8afa3452c671080569642e", "MessageId": "e93e9238-f9f8-4bf4-bf5b-9a0cae8a0ebc" } ] }

这里我只关注“Body”属性值。我做了一些不成功的尝试,如:

 jsawk -a 'return this.Body' 

 awk -v k="Body" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]} 

但这还不够。任何人都可以帮我这个吗?

4 个答案:

答案 0 :(得分:77)

在命令行上解析json有jq

 jq '.Body'

访问jq:https://stedolan.github.io/jq/

答案 1 :(得分:12)

TL;博士

$ cat /tmp/so.json | underscore select '.Messages .Body' 
["172.16.1.42|/home/480/1234/5-12-2013/1234.toSort"]

Javascript CLI工具

您可以使用Javascript CLI工具,例如

实施例

选择name的所有addons个孩子:

underscore select ".addons > .name"

underscore-cli提供其他人real world examples以及json:select() doc

答案 2 :(得分:5)

同样使用Bash regexp。应该能够抢夺任何键/值对。

key="Body"
re="\"($key)\": \"([^\"]*)\""

while read -r l; do
    if [[ $l =~ $re ]]; then
        name="${BASH_REMATCH[1]}"
        value="${BASH_REMATCH[2]}"
        echo "$name=$value"
    else
        echo "No match"
    fi
done

可以调整正则表达式以匹配多个空格/制表符或换行符。如果值已嵌入",则无效。这是一个例证。最好使用一些“工业”解析器:)

答案 3 :(得分:1)

这是一种粗略的方法:将JSON转换为bash变量到eval

这仅适用于:

  • 不包含嵌套数组的JSON,
  • 来自可靠来源的JSON(否则它可能会混淆您的shell脚本,也许它甚至可能会损害您的系统,您已被警告

嗯,是的,它使用PERL来完成这项工作,感谢CPAN,但它足够小,可以直接包含在脚本中,因此调试快速简便:

json2bash() {
perl -MJSON -0777 -n -E 'sub J {
my ($p,$v) = @_; my $r = ref $v;
if ($r eq "HASH") { J("${p}_$_", $v->{$_}) for keys %$v; }
elsif ($r eq "ARRAY") { $n = 0; J("$p"."[".$n++."]", $_) foreach @$v; }
else { $v =~ '"s/'/'\\\\''/g"'; $p =~ s/^([^[]*)\[([0-9]*)\](.+)$/$1$3\[$2\]/;
$p =~ tr/-/_/; $p =~ tr/A-Za-z0-9_[]//cd; say "$p='\''$v'\'';"; }
}; J("json", decode_json($_));'
}

eval "$(json2bash <<<'{"a":["b","c"]}')"

一样使用它 但是,没有经过严格测试。更新,警告和更多示例请参阅我的GIST

更新

(不幸的是,以下是仅限链接的解决方案,因为C代码很远 这里复制的时间太长了。)

对于那些不喜欢上述解决方案的人, 现在有C program json2sh 哪个(希望安全地)将JSON转换为shell变量。 与perl代码段相比,它可以处理任何JSON, 只要它形成良好。

注意事项:

  • json2sh未经过多次测试。
  • json2sh可能会创建以shellshock模式() {
  • 开头的变量

我写了json2sh以便能够使用Shell后处理.bson

bson2json()
{
printf '[';
{ bsondump "$1"; echo "\"END$?\""; } | sed '/^{/s/$/,/';
echo ']';
};

bsons2json()
{
printf '{';
c='';
for a;
do
  printf '%s"%q":' "$c" "$a";
  c=',';
  bson2json "$a";
done;
echo '}';
};

bsons2json */*.bson | json2sh | ..

说明:

  • bson2json转储.bson文件,使记录成为JSON数组
    • 如果一切正常,则会应用END0 - 标记,否则您会看到类似END1的内容。
    • 需要END - 标记,否则将显示空.bson个文件。
  • bsons2json将一堆.bson个文件作为对象转储,其中bson2json的输出由文件名索引。

然后由json2sh对其进行后处理,以便您可以使用grep / source / eval /等。你需要什么,将值带入shell。

这样您就可以在shell级别快速处理MongoDB转储的内容,而无需先将其导入MongoDB。