members.json
comme ci-dessous.{
"took": 670,
"timed_out": false,
"_shards": {
"total": 8,
"successful": 8,
"failed": 0
},
"hits": {
"total": 74,
"max_score": 1,
"hits": [
{
"_index": "2000_270_0",
"_type": "Medical",
"_id": "02:17447847049147026174478:174159",
"_score": 1,
"_source": {
"memberId": "0x7b93910446f91928e23e1043dfdf5bcf",
"memberFirstName": "Uri",
"memberMiddleName": "Prayag",
"memberLastName": "Dubofsky"
}
},
{
"_index": "2000_270_0",
"_type": "Medical",
"_id": "02:17447847049147026174478:174159",
"_score": 1,
"_source": {
"memberId": "0x7b93910446f91928e23e1043dfdf5bcG",
"memberFirstName": "Uri",
"memberMiddleName": "Prayag",
"memberLastName": "Dubofsky"
}
}
]
}
}
Je veux l'analyser en utilisant le script bash
obtenir uniquement la liste du champ memberId
.
memberIds
-----------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
.bashrc
:function getJsonVal() {
if [ \( $# -ne 1 \) -o \( -t 0 \) ]; then
echo "Usage: getJsonVal 'key' < /tmp/file";
echo " -- or -- ";
echo " cat /tmp/input | getJsonVal 'key'";
return;
fi;
cat | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["'$1'"]';
}
Et puis appelé:
$ cat members.json | getJsonVal "memberId"
Mais ça jette:
Traceback (most recent call last):
File "<string>", line 1, in <module>
KeyError: 'memberId'
Si vous utilisiez:
$ cat members.json | \
python -c 'import json,sys;obj=json.load(sys.stdin);print obj;'
vous pouvez inspecter la structure du dicton imbriqué obj
et voir que votre ligne d'origine doit se lire:
$ cat members.json | \
python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hits"]["hits"][0]["_source"]["'$1'"]';
à l'élément "memberId". De cette façon, vous pouvez conserver le Python comme un oneliner.
S'il y a plusieurs éléments dans l'élément "hits" imbriqué, alors vous pouvez faire quelque chose comme:
$ cat members.json | \
python -c '
import json, sys
obj=json.load(sys.stdin)
for y in [x["_source"]["'$1'"] for x in obj["hits"]["hits"]]:
print y
'
La solution de Chris Down est meilleure pour trouver une valeur unique pour des clés (uniques) à n'importe quel niveau.
Avec mon deuxième exemple qui imprime plusieurs valeurs, vous atteignez les limites de ce que vous devriez essayer avec une doublure, à ce stade, je ne vois pas de raison de faire la moitié du traitement en bash, et passerait à un [Python.
Une autre façon de le faire en bash utilise jshon . Voici une solution à votre problème en utilisant jshon
:
$ jshon -e hits -e hits -a -e _source -e memberId -u < foo.json
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Le -e
les options extraient les valeurs du json. Le -a
parcourt le tableau et le -u
décode la chaîne finale.
Eh bien, votre clé n'est clairement pas à la racine de l'objet. Essayez quelque chose comme ceci:
json_key() {
python -c '
import json
import sys
data = json.load(sys.stdin)
for key in sys.argv[1:]:
try:
data = data[key]
except TypeError: # This is a list index
data = data[int(key)]
print(data)' "$@"
}
Cela a l'avantage de ne pas simplement injecter de la syntaxe dans Python, ce qui pourrait provoquer une rupture (ou pire, l'exécution de code arbitraire).
Vous pouvez alors l'appeler comme ceci:
json_key hits hits 0 _source memberId < members.json
Une autre alternative est jq :
$ cat members.json | jq -r '.hits|.hits|.[]|._source|.memberId'
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Voici une solution bash.
find_members.sh
ajouter la ligne suivante au fichier + enregistrer
#!/bin/bash
echo -e "\nmemberIds\n---------"
cat members.json | grep -E 'memberId'|awk '{print$2}' | cut -d '"' -f2
chmod +x find_members.sh
Maintenant, lancez-le:
$ ./find_members.sh
memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Suivant ce fil J'utiliserais json.tool en python:
python -m json.tool members.json | awk -F'"' '/memberId/{print $4}'
En utilisant deepdiff vous n'avez pas besoin de connaître les clés exactes:
import json
from deepdiff import DeepSearch
DeepSearch(json.load(open("members.json", "r")), 'memberId', verbose_level=2)['matched_paths'].values()