【问题标题】:How can I get a JSON field value without `jq`?如何在没有 `jq` 的情况下获取 JSON 字段值?
【发布时间】: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"
}

【问题讨论】:

    标签: json linux awk sed grep


    【解决方案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),从值周围去除引号也很简单。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多