jq: ключ друку та значення для кожного запису в об'єкті


79

Як змусити jq взяти json так:

{
  "host1": { "ip": "10.1.2.3" },
  "host2": { "ip": "10.1.2.2" },
  "host3": { "ip": "10.1.18.1" }
}

і згенеруйте цей результат:

host1, 10.1.2.3
host2, 10.1.2.2
host3, 10.1.18.1

Мене не цікавить форматування, я просто не можу зрозуміти, як отримати доступ до імені та значення ключа.

Відповіді:


124

Щоб отримати клавіші верхнього рівня у вигляді потоку, ви можете скористатися вбудованою функцією keys[] . Отже, одним із вирішень вашої конкретної проблеми буде:

jq -r 'keys[] as $k | "\($k), \(.[$k] | .ip)"' 

keysвиробляє імена ключів у відсортованому порядку; якщо ви хочете, щоб вони були в оригінальному порядку, використовуйте keys_unsorted.

Іншою альтернативою, яка видає ключі в оригінальному порядку, є:

jq -r 'to_entries[] | "\(.key), \(.value | .ip)"'

Вихід CSV та TSV

Тут також варто розглянути фільтри @csv та @tsv, наприклад

jq -r 'to_entries[] | [.key, .value.ip] | @tsv'

виробляє:

host1   10.1.2.3
host2   10.1.2.2
host3   10.1.18.1

Вбудовані об'єкти

Якщо цікаві ключі вбудовані, як у наступному прикладі, jq-фільтр потрібно було б змінити за показаними рядками.

Вхідні дані:

{
  "myhosts": {
    "host1": { "ip": "10.1.2.3" },
    "host2": { "ip": "10.1.2.2" },
    "host3": { "ip": "10.1.18.1" }
  }
}

Модифікація:

jq -r '.myhosts | keys[] as $k | "\($k), \(.[$k] | .ip)"'

Припустимо, у ключі ".ip" є пробіли, наприклад, "ip-адреса", як уникнути лапок, що оточують ключ, враховуючи, що ви знаходитесь на третьому рівні цитованого рядка, якщо це має сенс?
Сайчовський

1
Так, це має сенс, і це гарне запитання, але пробачте, що я сказав, ви могли б легко відповісти на нього самі, оскільки відповідь полягає просто у ігноруванні потенційного ускладнення. Тобто, звичайним підходом було б цитування рядка з пробілами, et voilà.
пік

Я спробував це без успіху. Спробував уникнути цитат, але це не спрацювало, звідси питання.
Сайчовський,

1
@Saichovsky - Я перевірив, що це працює в jq 1.4, 1.5 та 1.6. Якщо ви використовуєте jq 1.3, вам доведеться писати .["id address"], як і раніше в звичайному випадку.
пік

47

Натрапив на дуже елегантне рішення

jq 'with_entries(.value |= .ip)'

Які витікають

{
  "host1": "10.1.2.3",
  "host2": "10.1.2.2",
  "host3": "10.1.18.1"
}

Ось фрагмент jqplay, з яким можна грати: https://jqplay.org/s/Jb_fnBveMQ

Функція with_entriesперетворює кожен об'єкт у списку об'єктів на пару ключ / значення, таким чином ми можемо отримати доступ .keyабо, .valueвідповідно, ми оновлюємо (перезаписуємо) кожен KV-елемент .valueз полем .ipза допомогою |=оператора оновлення


Це рішення - точна відповідь. Вибране рішення має додаткові функції, які є корисними, але не такими точними чи елегантними. Можливо, ви захочете додати стисле пояснення та повну команду.
Mike D

Чудово! Багато разів я використовував "to_entries []" просто тому, що не знав цього.
Lungang Fang
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.