Utilisation de jq pour analyser et afficher plusieurs champs dans un json en série

237

J'ai ce Json

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

En utilisant jq, j'aimerais afficher le nom et le prénom en série. Ainsi -

Stevie Wonder
Michael Jackson

Voilà jusqu'où je suis allé -

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

Mais il affiche

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

Remarquez ce qui suit -

  1. Les guillemets doubles que je ne veux pas.
  2. Le retour chariot que je ne veux pas.
  3. C'est brouillé. Ma requête affiche d'abord tous les prénoms, puis tous les noms de famille. Cependant, je veux l'avant-dernière, l'avant-dernière paire.
San
la source

Réponses:

340

Je recommande d'utiliser l'interpolation de chaînes:

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

référence

Eric Hartford
la source
13
c'est bien mieux si vos données sont des nombres
ozOli
203

Vous pouvez utiliser l' addition pour concaténer des chaînes.

Les chaînes sont ajoutées en étant jointes en une chaîne plus grande.

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

Ce qui précède fonctionne lorsque les deux firstet lastsont des chaînes. Si vous extrayez différents types de données (nombre et chaîne), nous devons convertir en types équivalents. Se référant à la solution sur cette question . Par exemple.

jq '.users[] | .first + " " + (.number|tostring)'
Abraham
la source
41
Pour éliminer les guillemets JSON, appelez jq avec l'option -r, par exemple jq -r '.users [] | .first + "" + .last '
pic
4
+1, mais pour mon cas d'utilisation, j'essaie de formater deux nombres sur la même ligne. Cette approche échoue car elle ne peut pas s'ajouter " "à un nombre. La réponse d'Eric donne un meilleur résultat pour cette affaire.
Synesso
9
@Synesso: (.numA|tostring) + " " + (.numB|tostring)devrait fonctionner. Ou interpolation de chaîne utiliser: "\(.numA) \(.numB)".
LS
Quand je l'ai fait jq '.users[] | .first + " " + .last', cela a très bien fonctionné, mais a provoqué une nouvelle ligne entre la valeur de .firstet .last. J'ai changé le " "pour "@"puis ai fait un sed 's/@/ /g'sur la sortie pour obtenir "John Smith" comme sortie. Quelque chose comme ça:jq '.users[] | .first + "@" + .last' | sed 's/@/ /g'
Bloodysock
33
jq '.users[]|.first,.last' | paste - -
optman
la source
14

Bien que les deux réponses ci-dessus fonctionnent bien si la clé, la valeur sont des chaînes, j'ai eu une situation pour ajouter une chaîne et un entier (erreurs jq en utilisant les expressions ci-dessus)

Condition: pour construire une URL sous 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
}

Solution:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'
machzqcq
la source
notez qu'il n'est pas nécessaire d'échapper à la parenthèse fermante et que vous vous trompez.
nymo
2
@nymo: Cela ne s'échappe pas. \(...)est l'interpolation de chaînes. Ici, il transforme le numérique .ServicePorten chaîne. Une interpolation pourrait être utilisée à la place des +signes pour raccourcir cette solution.
LS
12

Cela produira un tableau de noms

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

[
  "Stevie Wonder",
  "Michael Jackson"
]
TinyRoy
la source
4

Je me suis rapprochée de ce que je voulais en faisant quelque chose comme ça

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

Dont la sortie est assez proche de yaml pour que je puisse généralement l'importer dans d'autres outils sans trop de problème. (Je cherche toujours un moyen d'exporter basicallt un sous-ensemble de l'entrée json)

ThorSummoner
la source
1
Ce genre de travail dans mon cas, il suffit de laisser tomber le | tr -d '"' à la fin, et ajouter l'option -r à jq.
user842479
4

mon approche sera (votre exemple json n'est pas bien formé .. devinez c'est seulement un échantillon)

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

renvoie quelque chose comme ça

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

et grep la sortie avec une expression régulière.

Ganesh Chandrasekaran
la source