Использование jq для последовательного анализа и отображения нескольких полей в json

237

У меня есть этот Json

{
    "users": [
        {
            "first": "Stevie",
            "last": "Wonder"
        },
        {
            "first": "Michael",
            "last": "Jackson"
        }
    ]
}

Используя jq я хотел бы отображать имя и фамилию последовательно. Вот так -

Stevie Wonder
Michael Jackson

Вот как далеко я продвинулся -

jq '.users[].first, .users[].last'

Но это отображает

"Stevie"
"Michael"
"Wonder"
"Jackson"

Обратите внимание на следующее -

  1. Двойные кавычки, которые я не хочу.
  2. Возврат каретки, которую я не хочу.
  3. Это перемешано. Мой запрос сначала отображает все имена, а затем все фамилии. Тем не менее, я хочу первую-последнюю, первую-последнюю пару.
Сан -
источник

Ответы:

340

Я рекомендую использовать String Interpolation:

jq '.users[] | "\(.first) \(.last)"'

ссылка

Эрик Хартфорд
источник
13
это гораздо лучше, если ваши данные являются числами
ozOli
203

Вы можете использовать сложение для объединения строк.

Строки добавляются путем объединения в большую строку.

jq '.users[] | .first + " " + .last'

Выше работает, когда оба firstи lastстроки. Если вы извлекаете разные типы данных (число и строка), нам нужно преобразовать их в эквивалентные типы. Ссылаясь на решение по этому вопросу . Например.

jq '.users[] | .first + " " + (.number|tostring)'
Авраам
источник
41
Чтобы удалить кавычки JSON, вызовите jq с параметром -r, например, jq -r '.users [] | .first + "" + .last '
пик
4
+1, но в моем случае я пытаюсь отформатировать два числа в одной строке. Этот подход терпит неудачу, потому что он не может добавить " "к числу. Ответ Эрика дает лучший результат для этого случая.
Synesso
9
@Synesso: (.numA|tostring) + " " + (.numB|tostring)должно работать. Или используйте строку интерполяции вместо: "\(.numA) \(.numB)".
LS
Когда я это делал jq '.users[] | .first + " " + .last', это работало очень хорошо, но вызывало новую строку между значением .firstи .last. Я изменил " "к "@"а затем сделал sed 's/@/ /g'на выходе , чтобы получить «John Smith» , как выход. Как то так:jq '.users[] | .first + "@" + .last' | sed 's/@/ /g'
Bloodysock
14

В то время как оба приведенных выше ответа хорошо работают, если ключ, значение являются строками, у меня была ситуация, чтобы добавить строку и целое число (ошибки jq, используя вышеприведенные выражения)

Требование: построить URL ниже json

pradeep@seleniumframework>curl http://192.168.99.103:8500/v1/catalog/service/apache-443 | jq .[0]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   251  100   251    0     0   155k      0 --:--:-- --:--:-- --:--:--  245k
{
  "Node": "myconsul",
  "Address": "192.168.99.103",
  "ServiceID": "4ce41e90ede4:compassionate_wozniak:443",
  "ServiceName": "apache-443",
  "ServiceTags": [],
  "ServiceAddress": "",
  "ServicePort": 1443,
  "ServiceEnableTagOverride": false,
  "CreateIndex": 45,
  "ModifyIndex": 45
}

Решение:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'
machzqcq
источник
обратите внимание, что экранирование закрывающей скобки не требуется и будет ошибкой.
nymo
2
@nymo: Это не ускользает. \(...)это интерполяция строк. Здесь он превращает число .ServicePortв строку. Вместо +знаков можно использовать интерполяцию, чтобы сделать это решение короче.
LS
12

Это произведет массив имен

> jq '[ .users[] | (.first + " " + .last) ]' ~/test.json

[
  "Stevie Wonder",
  "Michael Jackson"
]
TinyRoy
источник
4

Я получил довольно близко к тому, что я хотел сделать что-то вроде этого

cat my.json | jq '.my.prefix[] | .primary_key + ":", (.sub.prefix[] | "    - " + .sub_key)' | tr -d '"' 

Вывод которого достаточно близок к yaml для меня, чтобы обычно импортировать его в другие инструменты без особых проблем. (Я до сих пор ищу способ экспортировать подмножество входных данных json)

ThorSummoner
источник
1
Такого рода работы в моем случае, просто бросьте | tr -d '"' в конце и добавить опцию -r в jq.
user842479
4

мой подход будет (ваш пример JSON не очень хорошо сформирован .. думаю, это только образец)

jq '.Front[] | [.Name,.Out,.In,.Groups] | join("|")'  front.json  > output.txt

возвращает что-то вроде этого

"new.domain.com-80|8.8.8.8|192.168.2.2:80|192.168.3.29:80 192.168.3.30:80"
"new.domain.com -443|8.8.8.8|192.168.2.2:443|192.168.3.29:443 192.168.3.30:443"

и grep вывод с регулярным выражением.

Ганеш Чандрасекаран
источник