【问题标题】:Read JSON data in a shell script [duplicate]在 shell 脚本中读取 JSON 数据 [重复]
【发布时间】:2013-12-27 14:33:34
【问题描述】:

在 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]} 

但这还不够。谁能帮我解决这个问题?

【问题讨论】:

标签: json bash shell


【解决方案1】:

命令行中有jq解析json:

 jq '.Body'

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

【讨论】:

【解决方案2】:

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 工具,例如

示例

选择addons 的所有name 子代:

underscore select ".addons > .name"

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

【讨论】:

    【解决方案3】:

    类似地使用 Bash 正则表达式。应该能够抓取任何键/值对。

    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
    

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

    【讨论】:

    • 这不适用于所有可能的键/值对。考虑"key": "value \"with quotes\""
    【解决方案4】:

    这是一种粗略的方法:将 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 &lt;&lt;&lt;'{"a":["b","c"]}')"一样使用它

    不过,没有经过大量测试。更新、警告和更多示例见我的GIST

    更新

    (不幸的是,以下是仅链接解决方案,因为 C 代码很远 太长,无法在此处复制。)

    对于所有不喜欢上述解决方案的人, 现在有一个C program json2sh 它(希望安全)将 JSON 转换为 shell 变量。 与perl sn-p 相比,它能够处理任何 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-Marker,否则您将看到类似 END1 的内容。
      • 需要END-Marker,否则不会显示空的.bson 文件。
    • bsons2json 将一堆 .bson 文件转储为一个对象,其中 bson2json 的输出由文件名索引。

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

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

    【讨论】:

    • 致反对者:我的回答有什么问题? eval 在这种情况下并不邪恶。我的回答解释了如何在 Shell 和 Perl 中访问 JSON。如果应用于问题中的 JSON 字符串,可以在${json_Messages_Body[0]} 中找到想要的结果,试试吧,这太明显了。如果你因为我的警告而投了反对票,那么,射击信使,但这仍然不能改变我的警告对于大多数 shell 脚本都是正确的事实。 那些会写安全脚本的人,通常不需要在stackoverflow上问。所以这里显然需要警告。
    • 我从 1992 年就开始使用 Perl,这里的代码对我来说不是显而易见的。你说它是安全的,但我不认为仅仅因为你这么说就一定是真的。过去没有专门针对安全性编写的 JSON 解析器一直是造成令人讨厌的安全错误的原因。如果此是在考虑到安全性的情况下编写的,请用可靠的来源更详细地记录这一点。
    • @tripleee:我确实不声称它是安全的。这在文本中明确说明:“这仅适用于.. JSON 来自可信赖的来源”。 (现在添加“和”以使其更清晰)。例如,它没有针对 shell-shock 进行强化,如果 JSON 包含嵌套数组,您会看到奇怪的错误。如果您对它的作用感到困惑,只需运行 jsonsource | json2bash,因为它将 shell 代码输出到标准输出。请注意,此代码当然可以改进以创建可以被认为更安全的东西。安全地做这件事意味着比这里介绍的要付出更多的努力。
    • 你说eval 不是邪恶的,这对我来说意味着你认为它可以安全使用。
    • 在可信赖的上下文中,eval 并不邪恶。
    猜你喜欢
    • 1970-01-01
    • 2017-01-06
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多