仅使用默认的 bash 解析 json

仅使用默认的 bash 解析 json

我搜索过并看到许多与我类似的问题,但没有一个答案能让我满意。

我的情况是:我正在编写一个将在服务器上运行的脚本。我有一个返回 json 主体的 curl 命令,我想选择具有特定键的所有值,并且我不能使用任何外部工具来解析 json (如 jq),我甚至没有 python,只有简单的 bash shell。

所以我的问题是如何使用默认 shell 来做到这一点?

同一个键会有多个值,我想创建这些值的数组。

一个示例 JSON:-

{
     "people":[
                 {
                     "id":"4568734",
                     "name":"suneel"
                 },
                 {
                     "id":"3678976",
                     "name":"adi"
                  }
             ]
   }

如果说“名称”,那么我想要数组(“suneel” “adi”)

注意:不使用外部工具,只使用 bash 命令。

答案1

可以使用如下的 Bash 函数:

function jsonValue() {
KEY=$1
num=$2
awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p
}

我已将此函数另存为,jsonVal然后使用获取此文件source jsonVal。您可以在脚本中很好地使用它。

它需要两个参数。第一个参数是属性名称。如果您需要所有值,请跳过第二个参数。如果需要特定值,您可以添加第二个参数,如下所示。

[root@localhost Desktop]# cat data.json | jsonValue id
4568734
3678976
[root@localhost Desktop]# cat data.json | jsonValue id 1
4568734
[root@localhost Desktop]# cat data.json | jsonValue id 2
3678976
[root@localhost Desktop]# cat data.json | jsonValue name
suneel
adi
[root@localhost Desktop]# cat data.json | jsonValue name 1
suneel
[root@localhost Desktop]# cat data.json | jsonValue name 2
adi
[root@localhost Desktop]#

希望这可以帮助。

答案2

使用除适当的 json 解析器之外的工具总是容易出现错误或安全问题。

最好的选择:如果您没有完成工作所需的工具,请让您的 IT/服务器管理员安装它们。


无论如何,以下内容至少对于您的示例有效:

使用grep -P

$ curl ... | grep -Po '"name":"\K[^"]*'
suneel
adi

正常情况下grep

$ curl ... | grep -o '"name":"[^"]*' | cut -d'"' -f4
suneel
adi

如果你"name"在外面有某个"people"你不想要的地方,这显然会失败。

答案3

这有点过头了,但我已经有一个应用程序可以读取 Gmail 元数据,以便将压缩并附加到 Gmail 邮件中的每日备份文件删除。文件格式与您的类似:

SAMPLE RECORD (REFORMATTED):
============================

{u'internalDate': u'1541947153000', 
u'historyId': u'1517343', 
u'payload': 
    {u'mimeType': u'multipart/mixed',
     u'headers': [
        {u'name': u'Return-Path', u'value': u'<[email protected]>'}, 
        {u'name': u'Received', u'value': u'from alien (node-ISP. [IPv6.Address])        by smtp.gmail.com with ESMTPSA id x184-v6sm1211487pfx.42.2018.11.11.06.39.15        for <[email protected]>        (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);        Sun, 11 Nov 2018 06:39:35 -0800 (PST)'}, 
        {u'name': u'Message-ID', u'value': u'<[email protected]>'}, 
        {u'name': u'From', u'value': u'root <[email protected]>'}, 
        {u'name': u'X-Google-Original-From', u'value': u'"root" <[email protected]>'}, 
        {u'name': u'Received', u'value': u'by alien (sSMTP sendmail emulation); Sun, 11 Nov 2018 07:39:13 -0700'}, 
        {u'name': u'Date', u'value': u'Sun, 11 Nov 2018 07:39:13 -0700'}, 
        {u'name': u'to', u'value': u'[email protected]'}, 
        {u'name': u'Subject', u'value': u'Daily-alien-Ubuntu-16.04-Backup-2018-11-11-Sunday.tar.gz.64'}
        ]
    }, 
u'snippet': u'', 
u'sizeEstimate': 18340047, 
u'threadId': u'1670336bc9ac099d', 
u'labelIds': [u'IMPORTANT', u'SENT', u'Label_12'], 
u'id': u'1670336bc9ac099d'
}

以下是大型 Bash 脚本的代码片段:

GrepLine () {

#https://askubuntu.com/questions/952467/extracting-a-specific-string-after-a-given-string-from-html-file-using-a-bash-sc

    End1="'"
    Srch2="{u'name': u'Date', u'value': u'"
    Srch3="{u'name': u'Subject', u'value': u'" # sometimes lower-case "subject"
    End3="'}"
    Srch4="u'sizeEstimate': "
    End4=","
    Srch5="u'labelIds': \[u'"
    End5="]"
    Srch6="u'id': u'" 

    # grep allows fast search (compiled C) and supports case insensitivity
    HeaderDate=$(grep -oiPm1 "$Srch2\K[^$End1]+" <<< "$plLine")
    HeaderSubject=$(grep -oiPm1 "$Srch3\K[^$End3]+" <<< "$plLine")
    [[ $HeaderSubject == "" ]] && HeaderSubject="GREP ERROR: Subject blank"

    Size=$(grep -oiPm1 "$Srch4\K[^$End4]+" <<< "$plLine")

    LabelIds=$(grep -oiPm1 "$Srch5\K[^$End5]+" <<< "$plLine")
    LabelIds="${LabelIds//\', u\'/$LabelSep}"
    TrimLen="${#LabelIds}"
    let TrimLen--
    LabelIds="${LabelIds:0:TrimLen}" # Remove trailing '
    # Convert "Label_12" to "Backup", etc.
    ReplaceLabels

    MessageId=$(grep -oiPm1 "$Srch6\K[^$End1]+" <<< "$plLine")

    # Some email messages have 50 extra spaces or more.
    HeaderSubject="${HeaderSubject%% }"

    # Convert HTML to ASCII, eg: Can&#39;t wear the same one
    # Replace external command: Line=$(sed 's/&amp;/\&/g; s/&lt;/\</g; 
    # s/&gt;/\>/g; s/&quot;/\"/g; s/&#39;/\'"'"'/g; s/&ldquo;/\"/g; 
    # s/&rdquo;/\"/g;' <<< "$Line") -- With faster builtin commands.
    HeaderSubject="${HeaderSubject//&nbsp;/ }"
    HeaderSubject="${HeaderSubject//&amp;/&}"
    HeaderSubject="${HeaderSubject//&lt;/<}"
    HeaderSubject="${HeaderSubject//&gt;/>}"
    HeaderSubject="${HeaderSubject//&quot;/'"'}"
    HeaderSubject="${HeaderSubject//&#39;/"'"}"
    HeaderSubject="${HeaderSubject//&ldquo;/'"'}" # TODO: ASCII/ISO for opening quote
    HeaderSubject="${HeaderSubject//&rdquo;/'"'}" # TODO: ASCII/ISO for closing quote

    # Truncate subject to 80 characters or whatever variable is set to
    HeaderSubject="${HeaderSubject:0:$SubjectTruncate}"
    HeaderSubject="${HeaderSubject//|/?}"       # Strip out Yad array separators
    HeaderSubject="${HeaderSubject//\--/==}"    # Yad doesn't like --
#    HeaderSubject="${HeaderSubject//\'/\"}"   # Yad doesn't like
    [[ $HeaderSubject == "" ]] && HeaderSubject="PARSING ERROR: Subject blank"

    # Convert date to YAD format
    HeaderDate=$(date -d "$HeaderDate" +'%Y-%m-%d')

} # GrepLine

相关内容