Usando jq para analisar e exibir vários campos em um json serialmente

237

Eu tenho esse Json

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

Usando jq, eu gostaria de exibir o nome e o sobrenome em série. Igual a -

Stevie Wonder
Michael Jackson

Foi assim que cheguei -

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

Mas mostra

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

Observe o seguinte -

  1. As aspas duplas que eu não quero.
  2. O retorno de carro que eu não quero.
  3. Está confuso. Minha consulta exibe todos os primeiros nomes primeiro e depois todos os sobrenomes. No entanto, quero o primeiro-último, primeiro-último par.
San
fonte

Respostas:

339

Eu recomendo usar a interpolação de string:

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

referência

Eric Hartford
fonte
13
este é muito melhor se seus dados são números
Ozoli
203

Você pode usar a adição para concatenar seqüências de caracteres.

As strings são adicionadas ao serem unidas em uma string maior.

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

O acima funciona quando ambos firste lastsão string. Se você estiver extraindo tipos de dados diferentes (número e string), precisamos converter para tipos equivalentes. Referindo-se à solução nesta questão . Por exemplo.

jq '.users[] | .first + " " + (.number|tostring)'
Abraão
fonte
41
Para eliminar as aspas JSON, chame jq com a opção -r, por exemplo, jq ​​-r '.users [] | .first + "" + .last '
peak
4
+1, mas no meu caso de uso, estou tentando formatar dois números na mesma linha. Essa abordagem falha porque não pode ser adicionada " "a um número. A resposta de Eric fornece um resultado melhor para este caso.
Synesso
9
@ Synesso: (.numA|tostring) + " " + (.numB|tostring)deve funcionar. Ou string uso de interpolação em vez disso: "\(.numA) \(.numB)".
LS
Quando fiz jq '.users[] | .first + " " + .last'isso, funcionou muito bem, mas causou uma nova linha entre o valor de .firste .last. Mudei o " "para "@"e depois fiz um sed 's/@/ /g'na saída para obter "John Smith" como saída. Algo como isto:jq '.users[] | .first + "@" + .last' | sed 's/@/ /g'
Bloodysock
33
jq '.users[]|.first,.last' | paste - -
optman
fonte
14

Embora ambas as respostas acima funcionem bem se key, value são strings, tive uma situação para anexar uma string e um número inteiro (erros jq usando as expressões acima)

Requisito: Para criar um URL abaixo 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
}

Solução:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'
machzqcq
fonte
observe que escapar do parêntese de fechamento não é necessário e pode ocorrer um erro.
Nymo
2
@nymo: Isso não está escapando. \(...)é interpolação de string. Aqui ele transforma numérico .ServicePortem string. A interpolação pode ser usada no lugar dos +sinais para diminuir esta solução.
LS
12

Isso produzirá uma variedade de nomes

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

[
  "Stevie Wonder",
  "Michael Jackson"
]
TinyRoy
fonte
4

Cheguei bem perto do que eu queria, fazendo algo assim

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

A saída está perto o suficiente do yaml para eu geralmente importá-lo para outras ferramentas sem muito problema. (Ainda estou procurando uma maneira de exportar um subconjunto da entrada json)

ThorSummoner
fonte
1
Esse tipo de funciona no meu caso, basta soltar o | tr -d '"' no final e adicione a opção -r à jq.
user842479 15/02/19
4

minha abordagem será (seu exemplo de json não está bem formado .. acho que é apenas uma amostra)

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

retorna algo como isto

"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"

e grep a saída com expressão regular.

Ganesh Chandrasekaran
fonte