use*_*040 15 command-line regex sed text-processing
我有这个json文本:
{
"buildStatus" : {
"status" : "ERROR",
"conditions" : [{
"status" : "OK",
"metricKey" : "bugs"
}, {
"status" : "ERROR",
"metricKey" : "test_success_density"
}, {
"status" : "OK",
"metricKey" : "vulnerabilities"
}
],
"periods" : []
}
}
Run Code Online (Sandbox Code Playgroud)
我想提取buildStatus的整体状态,即预期的输出是“ERROR”
"buildStatus" : {
"status" : "ERROR",
....
}
Run Code Online (Sandbox Code Playgroud)
我尝试了下面的 sed 表达式,但它不起作用,它返回OK:
status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
Byt*_*der 16
不要使用正则表达式解析复杂的嵌套数据结构,如 JSON 或 XML,使用适当的 JSON 解析器,如jshon.
首先你需要安装它:
sudo apt-get install jshon
Run Code Online (Sandbox Code Playgroud)
然后,您必须通过标准输入向其提供要解析的 JSON 数据,以便您可以使用管道 ( |)将另一个命令的输出重定向到那里,或者将文件重定向到它 ( < filename)。
提取所需数据所需的参数如下所示:
jshon -e "buildStatus" -e "status" -u
Run Code Online (Sandbox Code Playgroud)
-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
Run Code Online (Sandbox Code Playgroud)
要了解更多信息jshon,您可以阅读其在线访问的联机帮助页,或者只需键入man jshon。
hee*_*ayl 10
工作jq:
jq -r '.["buildStatus"]["status"]' file.json
Run Code Online (Sandbox Code Playgroud)
可以缩短为:
jq -r '.buildStatus.status' file.json
Run Code Online (Sandbox Code Playgroud)
-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
Run Code Online (Sandbox Code Playgroud)
如果尚未安装,请通过以下方式安装(在 Universe 存储库中可用):
sudo apt-get install jq
Run Code Online (Sandbox Code Playgroud)
如前所述,最好使用适当的 API 来解析复杂的结构化数据。Python 有一个json模块,我个人在我的脚本中使用了很多,并且很容易提取所需的字段,如下所示:
$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' < input.txt
ERROR
Run Code Online (Sandbox Code Playgroud)
这里发生的事情是我们将输入文件重定向到 python 的标准输入,并使用json.load(). 这变成了一个带有“buildStatus”键的python字典,它包含另一个带有“status”键的python字典。因此,我们只是打印出存储在另一个字典中的字典中键的值。相当简单。
除了简单之外,另一个优点是 python 和这个 API 都是预装的,并且默认随 Ubuntu 一起提供。
你能真正做到这一点的sed,但我强烈建议你使用具有写入处理JSON数据的工具更复杂的语言。例如,您可以尝试使用 perl 或 python。
现在,在您的简单示例中,您想要的只是第一次出现"status",因此您可以执行以下操作:
$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json
ERROR
Run Code Online (Sandbox Code Playgroud)
诀窍是使用-n以避免打印,然后如果该行匹配status( /status/),则删除除所需部分之外的所有内容s/.*:\s*"(.*)",/\1/,p打印该行并进行打印q。
就个人而言,我发现这个等效的 grep 命令要简单得多:
$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json
ERROR
Run Code Online (Sandbox Code Playgroud)
或者这个:
$ perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json
ERROR
Run Code Online (Sandbox Code Playgroud)
不过说真的,如果您打算解析 JSON 文件,请不要尝试手动执行此操作。使用合适的 JSON 解析器。
不是说你应该使用sed(我认为有人因为没有写强制性警告而对我投反对票)但是,如果你需要在下一行搜索一些东西,buildStatus因为你似乎在尝试自己的尝试,你需要告诉sed阅读N命令的下一行
$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR
Run Code Online (Sandbox Code Playgroud)
-n 在我们要求之前不要打印任何东西-r使用 ERE(与 相同-E)/buildStatus/N 找到这个模式并阅读下一行s/old/new/替换old为new.* 任意数量的任意字符\n 新队: "(.*)",保存在: "和之间出现的任何字符",\1 反向引用保存的模式p 打印我们处理过的部分