【问题标题】:Parsing JSON from shell script using JSON.sh使用 JSON.sh 从 shell 脚本解析 JSON
【发布时间】:2016-04-25 11:49:16
【问题描述】:

我正在使用 JSON.sh 解析 JSON 数据。我想从json 文件(test.json)中读取数据,其内容类似于,

{
  "/home/ukrishnan/projects/test.yml": {
    "LOG_DRIVER": "syslog",
    "IMAGE": "mysql:5.6"
  },
  "/home/ukrishnan/projects/mysql/app.xml": {
    "ENV_ACCOUNT_BRIDGE_ENDPOINT": "/u01/src/test/sample.txt"
  }
}

我尝试使用 JSON.sh 解析这个 JSON,

test_parser=`sh ./lib/JSON.sh < test/test.json`
echo $test_parser

打印出来,

["/home/ukrishnan/projects/test.yml","LOG_DRIVER"] "syslog" ["/home/ukrishnan/projects/test.yml","IMAGE"] "mysql:5.6" ["/home/ukrishnan/projects/test.yml"] {"LOG_DRIVER":"syslog","IMAGE":"mysql:5.6"} ["/home/ukrishnan/projects/mysql/app.xml","ENV_ACCOUNT_BRIDGE_ENDPOINT"] "/u01/src/test/sample.txt" ["/home/ukrishnan/projects/mysql/app.xml"] {"ENV_ACCOUNT_BRIDGE_ENDPOINT":"/u01/src/test/sample.txt"} [] {"/home/ukrishnan/projects/test.yml":{"LOG_DRIVER":"syslog","IMAGE":"mysql:5.6"},"/home/ukrishnan/projects/mysql/app.xml":{"ENV_ACCOUNT_BRIDGE_ENDPOINT":"/u01/src/test/sample.txt"}}

然而,同样的命令 (sh ./lib/JSON.sh &lt; test/test.json),如果我通过终端运行,它会打印换行符,

["/home/ukrishnan/projects/test.yml","LOG_DRIVER"]  "syslog"
["/home/ukrishnan/projects/test.yml","IMAGE"]   "mysql:5.6"
["/home/ukrishnan/projects/test.yml"]   {"LOG_DRIVER":"syslog","IMAGE":"mysql:5.6"}
["/home/ukrishnan/projects/mysql/app.xml","ENV_ACCOUNT_BRIDGE_ENDPOINT"]    "/u01/src/test/sample.txt"
["/home/ukrishnan/projects/mysql/app.xml"]  {"ENV_ACCOUNT_BRIDGE_ENDPOINT":"/u01/src/test/sample.txt"}
[]  {"/home/ukrishnan/projects/test.yml":{"LOG_DRIVER":"syslog","IMAGE":"mysql:5.6"},"/home/ukrishnan/projects/mysql/app.xml":{"ENV_ACCOUNT_BRIDGE_ENDPOINT":"/u01/src/test/sample.txt"}}

我想阅读这篇文章并将其分配给 bash 变量,例如,

file_name='/home/ukrishnan/projects/test.yml'
key='LOG_DRIVER'
value='syslog'

由于我对 shell 脚本和 grep 或 awk 几乎完全陌生,因此我不太了解如何实现这一点。对此的任何帮助将不胜感激。

【问题讨论】:

  • 尝试用双引号回显:echo "$test_parser"
  • @JoaoMorais 它的打印效果与在终端中执行相同(带有换行符)
  • 使用jq
  • @hek2mgl 嘿,对不起,我无法在服务器上安装任何东西 ;(
  • 然后使用能够解析json的编程语言。像pythonperlPHP...我敢肯定,如果不是全部都安装在服务器上。

标签: json bash shell awk grep


【解决方案1】:

如果您有兴趣,我写了一个JSON serializer / deserializer for gawk。保存该脚本并修改它,将# === FUNCTIONS === 上面的所有内容替换为以下内容:

#!/usr/bin/gawk -f

# capture JSON string from beginning to end into a scalar variable
{ json = json ORS $0 }

END {
    # objectify JSON string to the multilevel array "obj"
    deserialize(json, obj)

    for (filename in obj) {

        print "file_name=" quote(filename)

        for (key in obj[filename]) {

            # print key="value"
            print key "=" quote(obj[filename][key])
        }
    }
}

执行chmod 755 json.awk 并执行它。输出将如下所示:

$ ./json.awk test5.json
file_name="/home/ukrishnan/projects/mysql/app.xml"
ENV_ACCOUNT_BRIDGE_ENDPOINT="/u01/src/test/sample.txt"
file_name="/home/ukrishnan/projects/test.yml"
LOG_DRIVER="syslog"
IMAGE="mysql:5.6"

希望逻辑相当容易理解。如果您希望在每次循环迭代时输出filename=key=value=,请相应地修改嵌套的for 循环:

for (filename in obj) {
    for (key in obj[filename]) {
        print "file_name=" quote(filename)
        print "key=" quote(key)
        print "value=" quote(obj[filename][key])
    }
}

该更改将导致以下输出:

$ ./json.awk test5.json
file_name="/home/ukrishnan/projects/mysql/app.xml"
key="ENV_ACCOUNT_BRIDGE_ENDPOINT"
value="/u01/src/test/sample.txt"
file_name="/home/ukrishnan/projects/test.yml"
key="LOG_DRIVER"
value="syslog"
file_name="/home/ukrishnan/projects/test.yml"
key="IMAGE"
value="mysql:5.6"

无论如何,使用该输出,您可以在 BASH 中执行一些类似这样的愚蠢操作来填充变量并对其执行操作:

#!/bin/bash

./test.awk test5.json | while read -r line; do {
    eval $line
    [ "${line/=*/}" = "value" ] && {
        echo "bash: file_name=$file_name"
        echo "bash: key=$key"
        echo "bash: value=$value"
        echo "------"
    }
}; done

不过,从头到尾在 gawk 中完成所有处理而不弄乱多语言切换可能会更优雅。

回到 json.awk,如果您希望保持 json.awk 模块化以便在以后的项目中重用,您可以删除 # === FUNCTIONS === 以上的所有内容,创建一个单独的 main.awk,其中包含此顶部的代码块回答,@include "json.awk" 几乎可以在 END {...} 之外的任何地方(例如,在 shbang 下方)作为辅助库。

【讨论】:

    【解决方案2】:

    JSON.sh(来自http://json.org)提供了一种对 bash 友好的扁平化 JSON 文件的方法。您已经在问题中提供了它的外观。所以,扁平化的形式是这样的:

    [node] tab value
    

    您必须考虑在 UNIX 脚本中提取您想要的信息,您会注意到您感兴趣的行实际上遵循这种模式:

    • ["filename","key"] 选项卡 ["value"]

    在正则表达式中,我们替换:

    • 带有(.*)的文件名
    • 键与(.*)
    • 标签与\t
    • 值为(.*)

    我们可以分别用\1\2\3检索第一、第二和第三个匹配组。

    sed 中使用时,我们还注意到这些符号[]() 需要用反斜杠\ 进行转义,从而产生以下脚本:

    ./lib/JSON.sh < test/test.json | sed 's/\["\(.*\)","\(.*\)\"]\t"\(.*\)"/\1,\2,\3/;t;d'
    /home/ukrishnan/projects/test.yml,LOG_DRIVER,syslog
    /home/ukrishnan/projects/test.yml,IMAGE,mysql:5.6
    /home/ukrishnan/projects/mysql/app.xml,ENV_ACCOUNT_BRIDGE_ENDPOINT,/u01/src/test/sample.txt
    

    现在我们将这些行放在一个循环中,对于每一行,我们可以提取文件名、键、值:

    for line in $(./lib/JSON.sh < test/test.json | sed 's/\["\(.*\)","\(.*\)\"]\t"\(.*\)"/\1,\2,\3/;t;d')
    do
      IFS="," read -ra arr <<< $line
      filename=${arr[0]}
      key=${arr[1]}
      value=${arr[2]}
      cat <<EOF
    filename : $filename
    key      : $key
    value    : $value
    EOF
    done
    

    哪些输出:

    filename : /home/ukrishnan/projects/test.yml
    key      : LOG_DRIVER
    value    : syslog
    filename : /home/ukrishnan/projects/test.yml
    key      : IMAGE
    value    : mysql:5.6
    filename : /home/ukrishnan/projects/mysql/app.xml
    key      : ENV_ACCOUNT_BRIDGE_ENDPOINT
    value    : /u01/src/test/sample.txt
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 2014-05-05
      • 1970-01-01
      • 1970-01-01
      • 2016-06-21
      相关资源
      最近更新 更多