我搜索过并看到许多与我类似的问题,但没有一个答案能让我满意。
我的情况是:我正在编写一个将在服务器上运行的脚本。我有一个返回 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't wear the same one
# Replace external command: Line=$(sed 's/&/\&/g; s/</\</g;
# s/>/\>/g; s/"/\"/g; s/'/\'"'"'/g; s/“/\"/g;
# s/”/\"/g;' <<< "$Line") -- With faster builtin commands.
HeaderSubject="${HeaderSubject// / }"
HeaderSubject="${HeaderSubject//&/&}"
HeaderSubject="${HeaderSubject//</<}"
HeaderSubject="${HeaderSubject//>/>}"
HeaderSubject="${HeaderSubject//"/'"'}"
HeaderSubject="${HeaderSubject//'/"'"}"
HeaderSubject="${HeaderSubject//“/'"'}" # TODO: ASCII/ISO for opening quote
HeaderSubject="${HeaderSubject//”/'"'}" # 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