J'ai un fichier JSON qui doit être mis à jour dans certaines conditions.
Échantillon json
{
"Actions" : [
{
"value" : "1",
"properties" : {
"name" : "abc",
"age" : "2",
"other ": "test1"
}
},
{
"value" : "2",
"properties" : {
"name" : "def",
"age" : "3",
"other" : "test2"
}
}
]
}
J'écris un script qui utilise Jq pour faire correspondre une valeur et mettre à jour, comme indiqué ci-dessous
cat sample.json | jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"'
Sortie (imprimée sur le terminal)
{
"value": "1",
"properties": {
"name": "abc",
"age": "2",
"other ": "test1"
}
}
{
"value": "2",
"properties": {
"name": "def",
"age": "3",
"other": "no-test"
}
}
Bien que cette commande apporte les modifications nécessaires, elle affiche l'intégralité du JSON sur le terminal et ne modifie pas le fichier lui-même.
Veuillez indiquer s’il existe une option permettant à jq d’apporter des modifications directement sur le fichier (similaire à sed -i).
Cet article aborde la question de l'absence d'équivalent de l'option "-i" de sed, et en particulier de la situation décrite:
J'ai un tas de fichiers et écrire chacun dans un fichier séparé ne serait pas facile.
Il existe plusieurs options, du moins si vous travaillez sur un Mac, Linux ou un environnement similaire. Leurs avantages et inconvénients sont discutés à l'adresse http://backreference.org/2011/01/29/in-place-editing-of-files/ Je vais donc me concentrer sur trois techniques seulement. :
La première consiste simplement à utiliser "&&" dans le sens suivant:
jq ... INPUT > INPUT.tmp && mv INPUT.tmp INPUT
Une autre consiste à utiliser l'utilitaire sponge
(partie de GNU moreutils
):
jq ... INPUT | sponge INPUT
La troisième option peut être utile s'il est avantageux d'éviter de mettre à jour un fichier s'il n'y a aucune modification. Voici un script qui illustre une telle fonction:
#!/bin/bash
function maybeupdate {
local f="$1"
cmp -s "$f" "$f.tmp"
if [ $? = 0 ] ; then
/bin/rm $f.tmp
else
/bin/mv "$f.tmp" "$f"
fi
}
for f
do
jq . "$f" > "$f.tmp"
maybeupdate "$f"
done
Vous voudrez mettre à jour les objets d'action sans changer le contexte. En ayant le tuyau là-bas, vous modifiez le contexte pour chaque action individuelle. Vous pouvez contrôler cela avec des parenthèses.
$ jq --arg age "3" \
'(.Actions[] | select(.properties.age == $age).properties.other) = "no-test"' sample.json
Cela devrait donner:
{
"Actions": [
{
"value": "1",
"properties": {
"name": "abc",
"age": "2",
"other ": "test1"
}
},
{
"value": "2",
"properties": {
"name": "def",
"age": "3",
"other": "no-test"
}
}
]
}
Vous pouvez rediriger les résultats vers un fichier pour remplacer le fichier d'entrée. Il ne fera pas les mises à jour sur place d'un fichier comme le fait sed.
En utilisant ma réponse à une question en double
Assignment imprime l'intégralité de l'objet avec l'affectation exécutée afin que vous puissiez affecter une nouvelle valeur à
.Actions
du tableau Actions modifié..Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])
J'ai utilisé une instruction if mais nous pouvons utiliser votre code pour faire la même chose
.Actions=[.Actions[] | select (.properties.age == "3").properties.other = "no-test"]
Ce qui précède produira l’ensemble du json avec .Actions
édité . Jq n’a pas de fonctionnalité semblable à sed -i
, mais tout ce que vous avez à faire est de le rediriger dans un fichier sponge vers le fichier avec | sponge
jq '.Actions=([.Actions[] | if .properties.age == "3" then .properties.other = "no-test" else . end])' sample.json | sponge sample.json