web-dev-qa-db-fra.com

boucle à travers le tableau JSON dans le script Shell

Vous trouverez ci-dessous la sortie de la commande curl (informations de fichier sur la branche), besoin d'un script ou d'une commande pour imprimer le nom, le type de fichier et la taille du fichier.

J'ai essayé avec jq mais j'ai pu récupérer une seule valeur (jq '.values[].size')

{
  "path": {
    "components": [],
    "name": "",
    "toString": ""
  },
  "revision": "master",
  "children": {
    "size": 5,
    "limit": 500,
    "isLastPage": true,
    "values": [
      {
        "path": {
          "components": [
            ".gitignore"
          ],
          "parent": "",
          "name": ".gitignore",
          "extension": "gitignore",
          "toString": ".gitignore"
        },
        "contentId": "c9e472ef4e603480cdd85012b01bd5f4eddc86c6",
        "type": "FILE",
        "size": 224
      },
      {
        "path": {
          "components": [
            "Jenkinsfile"
          ],
          "parent": "",
          "name": "Jenkinsfile",
          "toString": "Jenkinsfile"
        },
        "contentId": "e878a88eed6b19b2eb0852c39bfd290151b865a4",
        "type": "FILE",
        "size": 1396
      },
      {
        "path": {
          "components": [
            "README.md"
          ],
          "parent": "",
          "name": "README.md",
          "extension": "md",
          "toString": "README.md"
        },
        "contentId": "05782ad495bfe11e00a77c30ea3ce17c7fa39606",
        "type": "FILE",
        "size": 237
      },
      {
        "path": {
          "components": [
            "pom.xml"
          ],
          "parent": "",
          "name": "pom.xml",
          "extension": "xml",
          "toString": "pom.xml"
        },
        "contentId": "9cd4887f8fc8c2ecc69ca08508b0f5d7b019dafd",
        "type": "FILE",
        "size": 2548
      },
      {
        "path": {
          "components": [
            "src"
          ],
          "parent": "",
          "name": "src",
          "toString": "src"
        },
        "node": "395c71003030308d1e4148b7786e9f331c269bdf",
        "type": "DIRECTORY"
      }
    ],
    "start": 0
  }
}

la sortie attendue devrait être quelque chose comme ci-dessous

.gitignore    FILE     224

Jenkinsfile   FILE     1396
6

Pour le cas d'utilisation fourni dans la question, la réponse de @ JigglyNaga est probablement meilleure que cela, mais pour une tâche plus compliquée, vous pouvez également parcourir les éléments de la liste en utilisant keys:

de file:

for k in $(jq '.children.values | keys | .[]' file); do
    ...
done

ou à partir d'une chaîne:

for k in $(jq '.children.values | keys | .[]' <<< "$MYJSONSTRING"); do
    ...
done

Donc par exemple vous pourriez utiliser:

for k in $(jq '.children.values | keys | .[]' file); do
    value=$(jq -r ".children.values[$k]" file);
    name=$(jq -r '.path.name' <<< "$value");
    type=$(jq -r '.type' <<< "$value");
    size=$(jq -r '.size' <<< "$value");
    printf '%s\t%s\t%s\n' "$name" "$type" "$size";
done | column -t -s$'\t'

si vous n'avez pas de nouvelle ligne pour les valeurs, vous pouvez le faire avec un seul appel jq à l'intérieur de la boucle ce qui le rend beaucoup plus rapide:

for k in $(jq '.children.values | keys | .[]' file); do
    IFS=$'\n' read -r -d '' name type size \
        <<< "$(jq -r ".children.values[$k] | .path.name,.type,.size" file)"
    printf '%s\t%s\t%s\n' "$name" "$type" "$size";
done | column -t -s$'\t'
7
pLumo

Extraire les membres

jq -c '.children.values[]|[.path.components[0],.type,.size]'
  • .children.values[] affiche chaque membre du tableau .values.
  • | redirige le résultat précédent vers le filtre suivant, un peu comme un tube Shell
  • [...,...,...] fait apparaître tous les termes à l'intérieur dans un seul tableau
  • Le -c L'option produit un format "compact" ie. un objet par ligne

Résultat:

[".gitignore","FILE",224]
["Jenkinsfile","FILE",1396]
["README.md","FILE",237]
...

Formatage du résultat

Si vous souhaitez générer une table parfaitement alignée, c'est une tâche mieux gérée par d'autres outils, tels que column ou paste .

jq -c '.children.values[]|[.path.components[0],.type,.size]' | column -t -s'[],"'
  • -t indique à column de deviner le nombre de colonnes en fonction de l'entrée
  • -s... spécifie le ou les caractères de délimitation

Résultat:

.gitignore   FILE       224
Jenkinsfile  FILE       1396
README.md    FILE       237

Cela repose sur les caractères [, ], , et " n'apparaissant pas dans vos noms de fichiers, ce qui n'est pas une hypothèse sûre.

paste peut également organiser plusieurs entrées côte à côte. Pour cela, nous pouvons supprimer complètement les structures JSON et générer des lignes brutes (chapeau à @muru):

jq -r '.children.values[]|.path.components[0],.type,.size' | paste - - -

paste - - - signifie 3 colonnes, toutes lues à partir de la même source. Cette fois, la seule hypothèse est que les noms de fichiers ne contiennent pas de nouvelles lignes.

15
JigglyNaga

jq peut rendre sa sortie dans une variété de formats: voir https://stedolan.github.io/jq/manual/#Formatstringsandescaping

Pour une sortie séparée par des tabulations:

$ jq -r '.children.values[] | [.path.name, .type, .size] | @tsv' file.json
.gitignore  FILE    224
Jenkinsfile FILE    1396
README.md   FILE    237
pom.xml FILE    2548
src DIRECTORY   
3
glenn jackman

Solution avec ramda-cli:

% curl ... | ramda -o tsv '.children.values' 'map flat' 'map props ["path.name", "type", "size"]'
.gitignore      FILE    224
Jenkinsfile     FILE    1396
README.md       FILE    237
pom.xml FILE    2548
src     DIRECTORY

Nous parcourons d'abord la liste de valeurs, puis mappons la liste avec flat pour convertir chaque entrée qui est une structure d'objet profonde en une entrée peu profonde, avec des clés séparées par des points.

Ensuite, nous pouvons à nouveau cartographier la liste et choisir les propriétés souhaitées en fonction de leurs chemins, représentés par des chaînes.

Finalement, -o tsv s'occupe de convertir la liste résultante des listes au format tsv.

Pour déboguer ou mieux comprendre ce qui se passe, vous pouvez vérifier ce que fait chaque argument en les supprimant un par un à la fin de la commande et en observant la différence de sortie à chaque étape. Ce sont simplement des opérations (ou fonctions) appliquées aux données une par une de gauche à droite.

1
raine

une solution de liner basée sur jtc et xargs:

bash $ jtc -x'<values>l[+0]<size>l[-1]' -y'<name>l' -y'<type>l' -y'<size>l' your.json | xargs -n3
.gitignore FILE 224
Jenkinsfile FILE 1396
README.md FILE 237
pom.xml FILE 2548
bash $ 

Remarque: il y a une irrégularité json dans votre fichier (la clé de taille n'est pas présente dans chaque enregistrement), pour l'exclure le premier argument -x est construit de cette façon (ne traite que les enregistrements où la taille est présente).

1
Dmitry L.