最近小山在编写 Bash 脚本的时候遇到一个处理 JSON 的问题,需要更改指定键的值。
Bash 的功能实现都是基于系统内的命令或二进制,但是 Linux 下并没有这样的工具,只有一个名为 jq 的工具,但它只能解析 JSON,并不能更改和生成。
所以。。。只能用现有的文本处理命令和 JQ 写一个出来,由于 JSON 的复杂性,Bash Shell 想完美处理几乎是不可能的,所以我只写了更改,没有添加和删除。
单个对象
如果要处理的 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 数据,当然,添加和删除也可以,只需要稍微改动一下就可以了。
示例文件下载 (不要直接复制上面的):https://cdn.mivm.cn/www.mivm.cn/archives/bash-shell-json/shell-json.zip
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 群找小山。
以上方法为小山原创,如有雷同,纯属巧合。
微信扫描二维码关注我们
如果觉得文章有帮助到你,可以点击下方的打赏按钮赞助下服务器费用。
文章评论
jq 可以修改的 ,setpath 函数很神奇,你可以去试试。