如何在没有 `jq` 的情况下获取 JSON 字段值?

Posted

技术标签:

【中文标题】如何在没有 `jq` 的情况下获取 JSON 字段值?【英文标题】:How can I get a JSON field value without `jq`? 【发布时间】:2020-08-12 21:10:51 【问题描述】:

我试图在有限的环境中从 JSON 中提取值,在该环境中我无法安装任何工具或从 Internet 下载任何内容。我在环境中可用的工具是busybox提供的基本工具,例如:awkgrepsed。没有像 Perl 和 Python 这样的编译器或解释器可用。

我试图解析的 JSON 有一个固定的方案,但它可以以任何有效的方式格式化,我总是需要获取字段 tag 的值。

可能的 JSON 示例:

"version":1,"name":"2","tag":"3"

    "version": 1,
    "tag":    "3",
    "name"   :"2"

【问题讨论】:

【参考方案1】:

这可能对你有用(GNU sed):

sed -nE '$!:a;N;$!ba;s/\n//g;s/"tag":[^"]*"([^"]*)"/\n\1\nTAG/g;/^[^\n]*\nTAG/P;D' file

这会将文件拖入内存,删除所有换行符,将标记值和标记反转到单独的连续行并打印这两行中的第一行。

替代方案,使用trgrepsed

tr -d '\n' <file | grep -o '"tag":[^"]*"[^"]*"' | sed -E 's/".*".*"(.*)"/\1/'

【讨论】:

【参考方案2】:

这将适用于您拥有的数据格式(即不适用于可能的完整 JSON 语法),在每个 UNIX 机器上的任何 shell 中使用任何 awk:

$ cat tst.awk
 rec = rec $0 
END 
    gsub(/^[ \t]*[][ \t]*|[ \t]*[][ \t]*$/,"",rec)
    while ( match(rec,/"[^"]+"[ \t]*:[ \t]]*("[^"]*"|[^,]*)/) ) 
        key = val = substr(rec,RSTART+1,RLENGTH-1)
        sub(/".*/,"",key)
        sub(/[^"]*"[ \t]]*:[ \t]*/,"",val)
        f[key] = val
        rec = substr(rec,RSTART+RLENGTH)
    
    print f[k]


$ echo '"version":1,"name":"2","tag":"3"' | awk -v k=tag -f tst.awk
"3"

$ cat file

    "version": 1,
    "tag":    "3",
    "name"   :"2"


$ awk -v k=tag -f tst.awk file
"3"

您可以轻松输出任何您喜欢的值:

$ awk -v k=name -f tst.awk file
"2"

$ awk -v k=version -f tst.awk file
1

并且修改以按您喜欢的任何顺序输出多个值,或者仅输出一个键的值(如果它在一个范围内或基于其他键值之间的关系等)将是微不足道的。例如:

$ cat tst.awk
 rec = rec $0 
END 
    split(keys,ks,/,/)
    gsub(/^[ \t]*[][ \t]*|[ \t]*[][ \t]*$/,"",rec)
    while ( match(rec,/"[^"]+"[ \t]*:[ \t]*("[^"]*"|[^,]*)/) ) 
        key = val = substr(rec,RSTART+1,RLENGTH-1)
        sub(/".*/,"",key)
        sub(/[^"]*"[ \t]*:[ \t]*/,"",val)
        f[key] = val
        rec = substr(rec,RSTART+RLENGTH)
    
    if ( (f["version"] > 0) && (f["name"] != f["tag"]) ) 
        for (i=1; i in ks; i++) 
            k = ks[i]
            print k, f[k]
        
    


$ awk -v keys=tag,version,name -f tst.awk file
tag "3"
version 1
name "2"

如果您不想要它们,只需在f[key] = val 正上方的循环中添加gsub(/^"|"$/,"",val),从值周围去除引号也很简单。

【讨论】:

以上是关于如何在没有 `jq` 的情况下获取 JSON 字段值?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jq 将任意简单 JSON 转换为 CSV?

Curl 与jq 发起json请求

如何使用 jq 从复杂的 JSON 文件中获取简单的 JSON 数据文件

如何在上传之前获取文件名并在没有 fakepath 的情况下传递到另一个文本输入字段

如何使用 jq 从 JSON 中获取键名

使用 jq 在 JSON 中连接 2 个字段