在bash脚本中使用python函数 - 解析JSON

时间:2013-12-05 13:09:55

标签: python json bash

我有一个bash脚本,旨在解析JSON格式的数据。我从这个论坛的早期查询中了解到,bash不擅长解析JSON,因此打算使用python函数进行解析:

以下是代码段:

#!/bin/bash

set -e

declare -a data_id
declare -a data_tid

function parse_data () {
    python <<EOF
import json
parsed = json.loads('''${@}''')

data_id = []
data_tid = []
for child in parsed['params']['children'][0]:
    print 'id: %s' % (child['data']['id'])
    data_id.append(child['data']['id'])
    print 'tid: %s' % (child['data']['tid'])
    data_tid.append(child['data']['tid'])
EOF
}

json=$(get_json_output)
parse_data $json

存储在'json'中的数据如下所示:

{
    "cid": "1",
    "code": null,
    "error": null,
    "params": {
        "children": [
            {
                "value": {
                    "id": "0123456789",
                    "tid": "a.b.c"
                },
                "data": {
                    "id": "0987654321",
                    "tid": "p.q.r"
                },
                "tid": "m.n.o.p",
            }
        ],
        "tid": "m.n.o.p"
    },
    "reason": null,
    "result": true
}

我希望脚本能够将“数据”下的“id”和“tid”字段提取到单独的数组中。但脚本执行失败如下:

root@ubuntu# ./abc.sh 
Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
TypeError: string indices must be integers

知道什么是错的吗?

4 个答案:

答案 0 :(得分:2)

离开[0]

for child in parsed['params']['children']:

否则您循环遍历children列表中第一个条目的键。

或者,如果该列表中只有一个条目,请不要循环,而是直接分配:

child = parsed['params']['children'][0]
print 'id: %s' % (child['data']['id'])
port_id.append(child['data']['id'])
print 'tid: %s' % (child['data']['tid'])
port_tid.append(child['data']['tid'])

答案 1 :(得分:0)

你只指儿童名单的第一项。 所以“孩子”实际上是字典的关键。

你应该从FOR循环中删除[0]

答案 2 :(得分:0)

这一行:

for child in parsed['params']['children'][0]:
    ...

parsed['params']['children'][0]不是列表。

将其更改为

for child in parsed['params']['children']:
    ...

# this one only for testing
for child in [parsed['params']['children'][0]]:
    ...

# also for testing
child = parsed['params']['children'][0]

答案 3 :(得分:0)

如果首先编写Python脚本,然后尝试将其嵌入到bash脚本中,您会发现这更容易调试。这是调试版本:

import json, sys

parsed = json.load(sys.stdin)

port_id = []
port_tid = []
for child in parsed['params']['children']:
    print 'id: %s' % (child['data']['id'])
    port_id.append(child['data']['id'])
    print 'tid: %s' % (child['data']['tid'])
    port_tid.append(child['data']['tid'])

其次,您的json数据中存在错误。我想你的意思是:

{
    "cid": "1",
    "code": null,
    "error": null,
    "params": {
        "children": [
            {
                "value": {
                    "id": "0123456789",
                    "tid": "a.b.c"
                },
                "data": {
                    "id": "0987654321",
                    "tid": "p.q.r"
                },
                "tid": "m.n.o.p"
            },
            {
               "value": {
                    "id": "0987654321",
                    "tid": "a.b.c"
                },
                "data": {
                    "id": "0123456789",
                    "tid": "p.q.r"
                },
                "tid": "m.n.o.p"
            }
        ],
        "tid": "m.n.o.p"
    },
    "reason": null,
    "result": true
}

最后,您仍需要将输出加载到Bash数组中。这是我的解决方案:

#!/bin/bash

set -e

parse_ids() { python -c '
import json, sys
parsed = json.load(sys.stdin)
print u"\n".join(c["data"]["id"] for c in parsed["params"]["children"])'
}

parse_tids() { python -c '
import json, sys
parsed = json.load(sys.stdin)
print u"\n".join(c["data"]["tid"] for c in parsed["params"]["children"])'
}

#json=$(get_json_output)
json=$(</dev/stdin)

declare -a port_id
mapfile -t port_id < <(echo "$json" | parse_ids)
echo "${port_id[@]}"

declare -a port_tid
mapfile -t port_tid < <(echo "$json" | parse_tids)
echo "${port_tid[@]}"
相关问题