web-dev-qa-db-fra.com

Regex avec la commande sed pour analyser le texte json

J'ai ce texte json:

{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

Je souhaite extraire le statut général de buildStatus, c'est-à-dire que la sortie attendue était "ERROR"

"buildStatus" : {
    "status" : "ERROR",
    ....
}

J'ai essayé l'expression sed ci-dessous, mais cela ne fonctionne pas, il retourne OK:

status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile

Qu'est-ce que je fais mal?

15
user1876040

Ne pas analyser des structures de données imbriquées complexes telles que JSON ou XML avec des expressions régulières, utilisez un analyseur JSON approprié, tel que jshon.

Vous devez d'abord l'installer:

Sudo apt-get install jshon

Vous devez ensuite lui fournir les données JSON à analyser via une entrée standard. Vous pouvez ainsi rediriger la sortie d'une autre commande avec un tube (|) ou y rediriger un fichier (< filename).

Les arguments nécessaires pour extraire les données souhaitées se présentent comme suit:

jshon -e "buildStatus" -e "status" -u
  • -e "buildStatus" sélectionne l'élément avec l'index "buildStatus" dans le dictionnaire de niveau supérieur.
  • -e "status" choisit l'élément avec l'index "status" dans le dictionnaire de deuxième niveau choisi ci-dessus.
  • -u convertit les données sélectionnées à partir de JSON en données standard (c’est-à-dire qu’il supprime ici les guillemets autour de la chaîne)

Ainsi, la commande que vous exécutez, en fonction de l'endroit où vous obtenez les données, ressemble à l'une de celles-ci:

jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u

Pour en savoir plus sur jshon, vous pouvez consulter sa page de manuel accessible en ligne ici ou en tapant simplement man jshon.

16
Byte Commander

Travail pour jqname__:

jq -r '.["buildStatus"]["status"]' file.json

Peut être raccourci à:

jq -r '.buildStatus.status' file.json

-r (--raw-output) génère la chaîne sans jsonname__, le formatage de chaîne i.e., sans guillemets.

Exemple:

% cat file.json                   
{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

% jq -r '.["buildStatus"]["status"]' file.json
ERROR

% jq -r '.buildStatus.status' file.json       
ERROR

S'il n'est pas déjà installé, installez-le par (disponible dans le référentiel Universe):

Sudo apt-get install jq 
10
heemayl

Comme il a été mentionné, l'analyse de données structurées complexes est préférable avec une API appropriée. Python a pour ce module json, que j'utilise souvent beaucoup dans mes scripts, et il est assez facile d'extraire les champs souhaités de la manière suivante:

$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' <  input.txt
ERROR

Ce qui se passe ici, c'est que nous redirigeons le fichier d'entrée vers le stdin de python et le lisons avec json.load(). Cela devient un dictionnaire python avec la clé "buildStatus", et il contient un autre dictionnaire python avec la clé "status". Ainsi, nous imprimons simplement la valeur d'une clé dans un dictionnaire qui est stocké dans un autre dictionnaire. Assez simple.

Outre la simplicité, un autre avantage est que python et cette API sont tous préinstallés et livrés avec Ubuntu par défaut.

9
Sergiy Kolodyazhnyy

Vous pouvez le faites réellement dans sed, mais je vous exhorte vivement à utiliser un langage plus sophistiqué comportant des outils permettant de gérer les données JSON. Vous pouvez essayer Perl ou Python, par exemple.

Maintenant, dans votre exemple simple, tout ce que vous voulez est la première occurrence de "status", vous pouvez donc:

$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json 
ERROR

L'astuce consiste à utiliser -n pour éviter l'impression. Si la ligne correspond à status (/status/), vous supprimez tout sauf la partie souhaitée s/.*:\s*"(.*)",/\1/, print et quit.


Personnellement, je trouve cette commande équivalente grep beaucoup plus simple:

$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json 
ERROR

Ou celui-ci:

$ Perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json 
ERROR

Sérieusement, si vous envisagez d'analyser des fichiers JSON, n'essayez pas de le faire manuellement. Utilisez un analyseur JSON approprié.

6
terdon

Ne vous dites pas devrait utilisez sed(je pense que quelqu'un m'a voté contre pour ne pas avoir écrit l'avertissement obligatoire), mais si vous devez rechercher quelque chose sur la suivante ligne à buildStatusas vous semblez essayer dans votre propre tentative, vous devez indiquer à sedde lire la ligne suivante avec la commande Nname__

$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR

Remarques:

  • -n n'imprime rien jusqu'à ce que nous le demandions
  • -r use ERE (identique à -E)
  • /buildStatus/N trouve ce modèle et lit également la ligne suivante
  • s/old/new/ remplace oldpar newname__
  • .* n'importe quel nombre de caractères quelconques sur la ligne
  • \n newline
  • : "(.*)", enregistre tous les caractères apparaissant entre : " et ",
  • \1 référence arrière au modèle enregistré
  • paffiche la partie sur laquelle nous avons travaillé
4
Zanna

Juste un autre outil Json appelé json ( https://github.com/trentm/json )

$ json buildStatus.status < file.json
ERROR

Cette étude de cas est trompeuse: il semble que les outils ne fonctionnent pas. Vous pouvez également utiliser json pour modifier les fichiers json:

$ json -e 'this.buildStatus.status="not error"' < file.json > new.json

ou même...

$ json -e 'this.buildStatus.status="no errors"' < file.json | json -e 'this.buildStatus.status
no errors

documentation dans: http://trentm.com/json/


si non installé:

  • noeud d'installation
  • et Sudo npm install -g json
0
JJoao

Une explication typique explique pourquoi sedet les outils de traitement de flux de texte similaires ne sont pas bien équipés pour analyser des données structurées telles que JSON et XML. Je ne l’ai pas sous la main, mais c’est là-bas, et j’estime que les expressions nécessaires dans presque toutes les situations, sans doute, deviennent rapidement très complexes, tandis que les outils alternatifs conçus spécifiquement pour analyser la structure sont plus efficaces. élégant, lisible et efficace à la même analyse.

Comme mur a mis dans un commentaire , jqdevrait être le bon outil pour le travail. Je peux également en garantir le fait que je suis personnellement très heureux de le voir remplacer plusieurs fois lorsque j’ai essayé d’analyser les mêmes données sans succès ou presque. Il contient même une grande capacité de formatage et de contrôle de la sortie. Je le préfère à jsontoolpour une raison ou plus que j'oublie actuellement.

Byte Commander semble recommander jshonin autre réponse . Je n'ai pas utilisé cet outil, mais il me rappelle xmlstarletet sa syntaxe, ainsi qu'une présentation personnalisable pour la sortie.

0
Pysis