2016-12-14 77 views
4

我需要解析lsblk的输出。由于我是通过脚本来完成这项工作的,因此我需要使用标准格式的输出。因此我选择了JSON格式作为输出。下面是一些示例输出命令:用jq解析JSON格式

# lsblk -o NAME,MOUNTPOINT -J 
{ 
    "blockdevices": [ 
     {"name": "sda", "mountpoint": null, 
     "children": [ 
      {"name": "sda1", "mountpoint": "/sda1/mountpoint"}, 
      {"name": "sda2", "mountpoint": null, 
       "children": [ 
        {"name": "sda2_mapper", "mountpoint": "/sda2/mountpoint"} 
       ] 
      }, 
      {"name": "sda3", "mountpoint": null}, 
      {"name": "sda4", "mountpoint": null} 
     ] 
     }, 
     {"name": "sdb", "mountpoint": null, 
     "children": [ 
      {"name": "sdb1", "mountpoint": "/sdb1/mountpoint"}, 
      {"name": "sdb2", "mountpoint": null} 
     ] 
     }, 
     {"name": "sdc", "mountpoint": null} 
    ] 
} 

我想提取所有最里面节点的名称,即,没有孩子的所有节点的名称。对于上述样品所需的输出为:

sda1 
sda2_mapper 
sda3 
sda4 
sdb1 
sdb2 
sdc 

我的首选工具是jq这是我最近才发现。我试过

# jq '.blockdevices[].children[]?.name?' 

但是,这只能过滤第一级别的名称。我也试过

# jq 'recurse(.name?)' 

但是这样会返回整个文件。

有没有办法只返回没有孩子的节点,不管它们嵌套得有多深?

PS:我能够执行bashawk中的要求。然而,我会选择使用像jq这样的工具的解决方案,其具体目的是解析json文件。

回答

1

我不认为这是做最简单的方法,但它似乎工作:

$ jq -r '.blockdevices[] | .. | objects | select(has("children")|not)| .name' tmp.json 
sda1 
sda2_mapper 
sda3 
sda4 
sdb1 
sdb2 
sdc 

它递归输出的JSON找到的每个值,过滤掉第一个东西是不是一个对象,然后是具有children键的任何对象。最后,您可以从剩余的每个对象中选择name值。

+0

我有一个快速跟进问题。当我捕获数组中的名称并随后调用挂载点时,挂载点将具有与其相应名称相同的索引,对吧?如果我不添加像“--sort-keys”这样的选项,该命令不会改变原始输出的顺序,对吗? – nautical

+0

正确。 '.name'过滤器前面的过滤器产生包含'name'和'mountpoint'键的字典。 – chepner

0

有了您的JSON输入以下命令:

jq '.. | scalars' 

发出 “叶子”,开头:

"sda" 
"sda1" 
"/sda1/mountpoint" 

使用-r(原始输出)剥离从字符串引号。