2016-12-14 2 views
4

Мне нужно разобрать вывод с lsblk. Поскольку я делаю это из сценария, мне нужен вывод в стандартизованном формате. Поэтому я выбрал формат JSON в качестве вывода. Вот команда, с каким-то выходом образца:Разбор JSON-формата с jq

# 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: Я в состоянии выполнить требование в bash или awk. Однако я бы предпочел решение с помощью инструмента, такого как 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 (сырой выход), чтобы лишить кавычки из строки ,

Смежные вопросы