Bash Shell 处理 JSON 数据

最近小山在编写 Bash 脚本的时候遇到一个处理 JSON 的问题,需要更改指定键的值。

Bash 的功能实现都是基于系统内的命令或二进制,但是 Linux 下并没有这样的工具,只有一个名为 jq 的工具,但它只能解析 JSON,并不能更改和生成。

所以。。。只能用现有的文本处理命令和 JQ 写一个出来,由于 JSON 的复杂性,Bash Shell 想完美处理几乎是不可能的,所以我只写了更改,没有添加和删除。

Bash Shell 处理 JSON 数据

单个对象

如果要处理的 JSON 是单个对象,只有一个花括号 {}。

这样处理起来是很简单的,因为不存在重复的键值。

逻辑:

先用grep根据键来匹配并获取数据行,为了精准匹配,最好加上 -w 参数。

因为值是分为 string、init、bool 三种类型,字符串需要加上引号,其他则不需要,所以需要判断值是什么类型,可以用grep判断。

如果值的类型为字符串,就在更改的时候加上引号。

除了需要判断值的类型,还需要判断是不是最后一个键,因为最后一个键结尾是没有逗号的。

最后用 sed 把数据行替换掉。

替换前的 JSON:

{
    “site_mivm”: “米V米”,
    “url_mivm”: “https://www.mivm.cn”,
    “cdn_mivm”: true,
    “type_mivm”: 1
}

完整示例:

#!/bin/bash

json=”test.json” # JSON 文件路径
json_data=”`jq . $json`” # JSON 数据

set_json() {
[ $# -lt 2 ] && return 1 # 参数数量小于 2 返回 1
jq -e .$1 $json >/dev/null 2>&1 || return 2 # 键值不存在返回 2
local json_key=$1
local json_value=””
local line_data=$(echo “$json_data” | grep -w “\”$json_key\”.*:” ) # 获取数据行
echo “$line_data” | grep -w “\”.*\”.*\”.*\”” >/dev/null 2>&1
[ $? -eq 0 ] && json_value=”\”$2\”” || json_value=$2 # 判断值是否为字符串
[ “${line_data:$((${#line_data}-1))}” = “,” ] && json_value=”${json_value},” # 判断数据行结尾是否有逗号
local json_new_data=$(echo “$json_data” | sed “s/$line_data/ \”$json_key\”: $json_value/”) # 替换数据行
echo “$json_new_data” | jq -e . >/dev/null 2>&1 || return 3 # 校验替换后的数据 失败返回 3
json_data=”$json_new_data” && echo “$json_data” > $json
}

set_json “site_mivm” “米V米 – 希望可以找到你想到的”

替换后的 JSON:

{
    “site_mivm”: “米V米 – 希望可以找到你想到的”,
    “url_mivm”: “https://www.mivm.cn”,
    “cdn_mivm”: true,
    “type_mivm”: 1
}

此方法可以非常方便的更改单个对象的 JSON 数据,当然,添加和删除也可以,只需要稍微改动一下就可以了。

示例文件下载 (不要直接复制上面的)

PS: 总比某些脚本更改一个键值写一个函数强

多个对象或数组

如果你遇到的 JSON 有多个对象或数组,比如这样的:

{
    “site”:[
        {
            “name”: “米V米”,
            “url”: “https://www.mivm.cn”
        },
        {
            “name”: “米V米”,
            “url”: “https://www.mivm.cn”
        },
        {
            “name”: “米V米”,
            “url”: “https://www.mivm.cn”
        }
    ],
    “cdn”: true,
    “type”: {
        “1”:”blog”,
        “2”:”blog”,
        “3”:”blog”
    }
}

那么,更改起来可能就有点麻烦了,因为就不能使用上面那种方法了,多个对象之间,键值是允许重复的,需要另辟奇径。

很可惜的是,小山想了一天也没想出来通用的方法,可以不受数量限制更改。

只能是有针对性的更改,如果你有完美处理的方法,或者想跟小山进行探讨,可以加入 QQ 群找小山。


以上方法为小山原创,如有雷同,纯属巧合。

如果你有更好的方法,欢迎加入 QQ 群和小山探讨。

微信公众号二维码

微信扫描二维码关注我们

点赞
  1. 路人甲说道:

    jq 可以修改的 ,setpath 函数很神奇,你可以去试试。

    Safari 11.0.3 Safari 11.0.3 Mac OS X  10.13.3 Mac OS X 10.13.3

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.