我有这个 json 文本:
{
"buildStatus" : {
"status" : "ERROR",
"conditions" : [{
"status" : "OK",
"metricKey" : "bugs"
}, {
"status" : "ERROR",
"metricKey" : "test_success_density"
}, {
"status" : "OK",
"metricKey" : "vulnerabilities"
}
],
"periods" : []
}
}
我想提取 buildStatus 的总体状态,即预期输出为“ERROR”
"buildStatus" : {
"status" : "ERROR",
....
}
我尝试了下面的 sed 表达式,但它不起作用,它返回OK
:
status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile
我究竟做错了什么?
答案1
不要使用正则表达式解析复杂的嵌套数据结构(如 JSON 或 XML),而要使用适当的 JSON 解析器,如jshon
。
首先你需要安装它:
sudo apt-get install jshon
然后,您必须通过标准输入向其提供 JSON 数据以进行解析,这样您就可以使用管道 ( |
) 将另一个命令的输出重定向到那里或将文件重定向到它 ( < filename
)。
提取所需数据所需的参数如下所示:
jshon -e "buildStatus" -e "status" -u
-e "buildStatus"
从顶级字典中选择具有“buildStatus”索引的元素。-e "status"
从上面选择的第二级字典中选择具有“状态”索引的元素。-u
将选定的数据从 JSON 转换为纯数据(即,这里删除了字符串周围的引号)
因此,您运行的命令(取决于您从哪里获取数据)看起来像下列命令之一:
jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u
要了解更多信息jshon
,您可以阅读其在线手册页这里或者直接输入man jshon
。
答案2
工作职位jq
:
jq -r '.["buildStatus"]["status"]' file.json
可以缩写为:
jq -r '.buildStatus.status' file.json
-r
( ) 输出不带字符串格式的--raw-output
字符串,即不带引号的字符串。json
例子:
% cat file.json
{
"buildStatus" : {
"status" : "ERROR",
"conditions" : [{
"status" : "OK",
"metricKey" : "bugs"
}, {
"status" : "ERROR",
"metricKey" : "test_success_density"
}, {
"status" : "OK",
"metricKey" : "vulnerabilities"
}
],
"periods" : []
}
}
% jq -r '.["buildStatus"]["status"]' file.json
ERROR
% jq -r '.buildStatus.status' file.json
ERROR
如果尚未安装,请通过以下方式安装(可在 Universe 存储库中找到):
sudo apt-get install jq
答案3
如上所述,使用适当的 API 解析复杂的结构化数据是更好的选择。Python 有json
一个模块,我个人在我的脚本中经常使用它,并且可以很容易地提取所需的字段,如下所示:
$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' < input.txt
ERROR
这里发生的事情是,我们将输入文件重定向到 Python 的标准输入,并使用 读取该文件json.load()
。这将成为具有键“buildStatus”的 Python 字典,并且它包含另一个具有“status”键的 Python 字典。因此,我们只是打印出存储在另一个字典中的字典中键的值。相当简单。
除了简单之外,另一个优点是 python 和这个 API 都是预装的,并默认随 Ubuntu 一起提供。
答案4
不是说你应该使用sed
(我认为有人因为我没有写强制性警告而对我投了反对票),但如果你需要在下一个行到,buildStatus
因为你似乎在尝试自己的尝试,你需要告诉使用命令sed
读取下一行N
$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR
笔记:
-n
在我们要求之前不要打印任何内容-r
使用 ERE (与 相同-E
)/buildStatus/N
找到这个模式并阅读下一行s/old/new/
old
用。。。来代替new
.*
行中任意数量的任意字符\n
新队: "(.*)",
: "
保存在和之间出现的任何字符",
\1
返回引用已保存的模式p
打印我们工作的部分