How to find and replace multiple field values using jq?
In the following json file,
{
"email": "xxx",
"pass": "yyy",
"contact": [
{
"id": 111,
"name": "AAA"
}
],
"lname": "YYY",
"name": "AAA",
"group": [
{
"name": "AAA",
"lname": "YYY",
}
],
I need to look for the key "name" and replace its value to "XXX" at all places. Which jq command does that ?
sed json jq
add a comment |
In the following json file,
{
"email": "xxx",
"pass": "yyy",
"contact": [
{
"id": 111,
"name": "AAA"
}
],
"lname": "YYY",
"name": "AAA",
"group": [
{
"name": "AAA",
"lname": "YYY",
}
],
I need to look for the key "name" and replace its value to "XXX" at all places. Which jq command does that ?
sed json jq
add a comment |
In the following json file,
{
"email": "xxx",
"pass": "yyy",
"contact": [
{
"id": 111,
"name": "AAA"
}
],
"lname": "YYY",
"name": "AAA",
"group": [
{
"name": "AAA",
"lname": "YYY",
}
],
I need to look for the key "name" and replace its value to "XXX" at all places. Which jq command does that ?
sed json jq
In the following json file,
{
"email": "xxx",
"pass": "yyy",
"contact": [
{
"id": 111,
"name": "AAA"
}
],
"lname": "YYY",
"name": "AAA",
"group": [
{
"name": "AAA",
"lname": "YYY",
}
],
I need to look for the key "name" and replace its value to "XXX" at all places. Which jq command does that ?
sed json jq
sed json jq
edited Oct 19 '18 at 19:53
Rui F Ribeiro
39.5k1479133
39.5k1479133
asked Oct 19 '18 at 12:12
user2181698user2181698
283
283
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
Using jq
based on the walk
function (needs a recent version):
jq 'walk(.name?="XXX")' file
If your jq
doesn't support the walk
function, just define it as:
jq '
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
walk(.name?="XXX")
' file
Credits: https://github.com/stedolan/jq/issues/963
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
add a comment |
jq's assignment operations can perform an update on as many locations at once as you can name and are made for this sort of situation. You can use
jq '(.. | .name?) |= "XXXX"'
to find every field called "name" anywhere and replace the value in each all at once with "XXXX", and output the resulting object.
This is just the ..|.a?
example from the recursive-descent documentation combined with update assignment.
It uses the recursive descent operator ..
to find every single value in the tree, then pulls out the "name" field from each of them with .name
, suppresses any errors from non-matching values with ?
, and then updates the object in all those places at once with "XXXX" using the update-assignment operator |=
, and outputs the new object.
This will work no matter what the file structure is and update every name field everywhere.
Alternatively, if the file always has this structure, and it's those particular "name" fields you want to change, not just any old name, you can also just list them out and assign to them as a group as well:
jq '(.name, .contact.name, .group.name) |= "XXXX"'
This does the same assignment to
- the "name" field of the top-level object;
- the "name" field of every object in the "contact" array; and
- the "name" field of every object in the "group" array.
all in one go. This is particularly useful if the file might have other name fields in there somewhere unrelated that you don't want to change. It finds just the three sets of locations named there and updates them all simultaneously.
If the value is just a literal like it is here then plain assignment with =
works too and saves you a character: (..|.name?)="XXXX"
- you'd also want this if your value is computed based on the whole top-level object. If instead you want to compute the new name based on the old one, you need to use |=
. If I'm not sure what to use, |=
generally has slightly nicer behaviour in the corner cases.
If you have multiple replacements to do, you can pipe them together:
jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'
will update both the "name" and "lname" fields everywhere, and output the whole updated object once.
A few other approaches that may work:
You could also be really explicit about what you're selecting with
(..|objects|select(has("name"))).name |= "XXXX"`
which finds everything, then just the objects, then just the objects that have a "name", then the name field on those objects, and performs the same update as before.
- If you're running the development version of jq (unlikely) then the
walk
function can also do the job:walk(.name?="XXXX")
. All the other versions will work on the latest released version, 1.5.
An alternative multi-update could be
jq '(..|has("name")?) += {name: "XXXX", lname: "1234"}'
which finds everything with a name and then sets both "name" and "lname" on each object using arithmetic update-assignment
*=
and the merging behaviour that+
has for objects.
add a comment |
alternatively, jtc
based solution:
bash $ jtc -w'<name>l+0' -u'"XXX"' your.json
{
"contact": [
{
"id": 111,
"name": "XXX"
}
],
"email": "xxx",
"group": [
{
"lname": "YYY",
"name": "XXX"
}
],
"lname": "YYY",
"name": "XXX",
"pass": "yyy"
}
bash $
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f476536%2fhow-to-find-and-replace-multiple-field-values-using-jq%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Using jq
based on the walk
function (needs a recent version):
jq 'walk(.name?="XXX")' file
If your jq
doesn't support the walk
function, just define it as:
jq '
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
walk(.name?="XXX")
' file
Credits: https://github.com/stedolan/jq/issues/963
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
add a comment |
Using jq
based on the walk
function (needs a recent version):
jq 'walk(.name?="XXX")' file
If your jq
doesn't support the walk
function, just define it as:
jq '
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
walk(.name?="XXX")
' file
Credits: https://github.com/stedolan/jq/issues/963
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
add a comment |
Using jq
based on the walk
function (needs a recent version):
jq 'walk(.name?="XXX")' file
If your jq
doesn't support the walk
function, just define it as:
jq '
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
walk(.name?="XXX")
' file
Credits: https://github.com/stedolan/jq/issues/963
Using jq
based on the walk
function (needs a recent version):
jq 'walk(.name?="XXX")' file
If your jq
doesn't support the walk
function, just define it as:
jq '
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
walk(.name?="XXX")
' file
Credits: https://github.com/stedolan/jq/issues/963
answered Oct 19 '18 at 13:02
olivoliv
1,651311
1,651311
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
add a comment |
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
Hi I get the following error. error: Invalid character walk(.name?="XXX") ^
– user2181698
Oct 19 '18 at 14:29
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
@user2181698 are you sure you're running that command on linux/unix?
– qubert
Oct 19 '18 at 14:57
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
Perhaps @user2181698 is using an unusual shell and neglected to mention it?
– Michael Hampton
Oct 19 '18 at 17:55
add a comment |
jq's assignment operations can perform an update on as many locations at once as you can name and are made for this sort of situation. You can use
jq '(.. | .name?) |= "XXXX"'
to find every field called "name" anywhere and replace the value in each all at once with "XXXX", and output the resulting object.
This is just the ..|.a?
example from the recursive-descent documentation combined with update assignment.
It uses the recursive descent operator ..
to find every single value in the tree, then pulls out the "name" field from each of them with .name
, suppresses any errors from non-matching values with ?
, and then updates the object in all those places at once with "XXXX" using the update-assignment operator |=
, and outputs the new object.
This will work no matter what the file structure is and update every name field everywhere.
Alternatively, if the file always has this structure, and it's those particular "name" fields you want to change, not just any old name, you can also just list them out and assign to them as a group as well:
jq '(.name, .contact.name, .group.name) |= "XXXX"'
This does the same assignment to
- the "name" field of the top-level object;
- the "name" field of every object in the "contact" array; and
- the "name" field of every object in the "group" array.
all in one go. This is particularly useful if the file might have other name fields in there somewhere unrelated that you don't want to change. It finds just the three sets of locations named there and updates them all simultaneously.
If the value is just a literal like it is here then plain assignment with =
works too and saves you a character: (..|.name?)="XXXX"
- you'd also want this if your value is computed based on the whole top-level object. If instead you want to compute the new name based on the old one, you need to use |=
. If I'm not sure what to use, |=
generally has slightly nicer behaviour in the corner cases.
If you have multiple replacements to do, you can pipe them together:
jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'
will update both the "name" and "lname" fields everywhere, and output the whole updated object once.
A few other approaches that may work:
You could also be really explicit about what you're selecting with
(..|objects|select(has("name"))).name |= "XXXX"`
which finds everything, then just the objects, then just the objects that have a "name", then the name field on those objects, and performs the same update as before.
- If you're running the development version of jq (unlikely) then the
walk
function can also do the job:walk(.name?="XXXX")
. All the other versions will work on the latest released version, 1.5.
An alternative multi-update could be
jq '(..|has("name")?) += {name: "XXXX", lname: "1234"}'
which finds everything with a name and then sets both "name" and "lname" on each object using arithmetic update-assignment
*=
and the merging behaviour that+
has for objects.
add a comment |
jq's assignment operations can perform an update on as many locations at once as you can name and are made for this sort of situation. You can use
jq '(.. | .name?) |= "XXXX"'
to find every field called "name" anywhere and replace the value in each all at once with "XXXX", and output the resulting object.
This is just the ..|.a?
example from the recursive-descent documentation combined with update assignment.
It uses the recursive descent operator ..
to find every single value in the tree, then pulls out the "name" field from each of them with .name
, suppresses any errors from non-matching values with ?
, and then updates the object in all those places at once with "XXXX" using the update-assignment operator |=
, and outputs the new object.
This will work no matter what the file structure is and update every name field everywhere.
Alternatively, if the file always has this structure, and it's those particular "name" fields you want to change, not just any old name, you can also just list them out and assign to them as a group as well:
jq '(.name, .contact.name, .group.name) |= "XXXX"'
This does the same assignment to
- the "name" field of the top-level object;
- the "name" field of every object in the "contact" array; and
- the "name" field of every object in the "group" array.
all in one go. This is particularly useful if the file might have other name fields in there somewhere unrelated that you don't want to change. It finds just the three sets of locations named there and updates them all simultaneously.
If the value is just a literal like it is here then plain assignment with =
works too and saves you a character: (..|.name?)="XXXX"
- you'd also want this if your value is computed based on the whole top-level object. If instead you want to compute the new name based on the old one, you need to use |=
. If I'm not sure what to use, |=
generally has slightly nicer behaviour in the corner cases.
If you have multiple replacements to do, you can pipe them together:
jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'
will update both the "name" and "lname" fields everywhere, and output the whole updated object once.
A few other approaches that may work:
You could also be really explicit about what you're selecting with
(..|objects|select(has("name"))).name |= "XXXX"`
which finds everything, then just the objects, then just the objects that have a "name", then the name field on those objects, and performs the same update as before.
- If you're running the development version of jq (unlikely) then the
walk
function can also do the job:walk(.name?="XXXX")
. All the other versions will work on the latest released version, 1.5.
An alternative multi-update could be
jq '(..|has("name")?) += {name: "XXXX", lname: "1234"}'
which finds everything with a name and then sets both "name" and "lname" on each object using arithmetic update-assignment
*=
and the merging behaviour that+
has for objects.
add a comment |
jq's assignment operations can perform an update on as many locations at once as you can name and are made for this sort of situation. You can use
jq '(.. | .name?) |= "XXXX"'
to find every field called "name" anywhere and replace the value in each all at once with "XXXX", and output the resulting object.
This is just the ..|.a?
example from the recursive-descent documentation combined with update assignment.
It uses the recursive descent operator ..
to find every single value in the tree, then pulls out the "name" field from each of them with .name
, suppresses any errors from non-matching values with ?
, and then updates the object in all those places at once with "XXXX" using the update-assignment operator |=
, and outputs the new object.
This will work no matter what the file structure is and update every name field everywhere.
Alternatively, if the file always has this structure, and it's those particular "name" fields you want to change, not just any old name, you can also just list them out and assign to them as a group as well:
jq '(.name, .contact.name, .group.name) |= "XXXX"'
This does the same assignment to
- the "name" field of the top-level object;
- the "name" field of every object in the "contact" array; and
- the "name" field of every object in the "group" array.
all in one go. This is particularly useful if the file might have other name fields in there somewhere unrelated that you don't want to change. It finds just the three sets of locations named there and updates them all simultaneously.
If the value is just a literal like it is here then plain assignment with =
works too and saves you a character: (..|.name?)="XXXX"
- you'd also want this if your value is computed based on the whole top-level object. If instead you want to compute the new name based on the old one, you need to use |=
. If I'm not sure what to use, |=
generally has slightly nicer behaviour in the corner cases.
If you have multiple replacements to do, you can pipe them together:
jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'
will update both the "name" and "lname" fields everywhere, and output the whole updated object once.
A few other approaches that may work:
You could also be really explicit about what you're selecting with
(..|objects|select(has("name"))).name |= "XXXX"`
which finds everything, then just the objects, then just the objects that have a "name", then the name field on those objects, and performs the same update as before.
- If you're running the development version of jq (unlikely) then the
walk
function can also do the job:walk(.name?="XXXX")
. All the other versions will work on the latest released version, 1.5.
An alternative multi-update could be
jq '(..|has("name")?) += {name: "XXXX", lname: "1234"}'
which finds everything with a name and then sets both "name" and "lname" on each object using arithmetic update-assignment
*=
and the merging behaviour that+
has for objects.
jq's assignment operations can perform an update on as many locations at once as you can name and are made for this sort of situation. You can use
jq '(.. | .name?) |= "XXXX"'
to find every field called "name" anywhere and replace the value in each all at once with "XXXX", and output the resulting object.
This is just the ..|.a?
example from the recursive-descent documentation combined with update assignment.
It uses the recursive descent operator ..
to find every single value in the tree, then pulls out the "name" field from each of them with .name
, suppresses any errors from non-matching values with ?
, and then updates the object in all those places at once with "XXXX" using the update-assignment operator |=
, and outputs the new object.
This will work no matter what the file structure is and update every name field everywhere.
Alternatively, if the file always has this structure, and it's those particular "name" fields you want to change, not just any old name, you can also just list them out and assign to them as a group as well:
jq '(.name, .contact.name, .group.name) |= "XXXX"'
This does the same assignment to
- the "name" field of the top-level object;
- the "name" field of every object in the "contact" array; and
- the "name" field of every object in the "group" array.
all in one go. This is particularly useful if the file might have other name fields in there somewhere unrelated that you don't want to change. It finds just the three sets of locations named there and updates them all simultaneously.
If the value is just a literal like it is here then plain assignment with =
works too and saves you a character: (..|.name?)="XXXX"
- you'd also want this if your value is computed based on the whole top-level object. If instead you want to compute the new name based on the old one, you need to use |=
. If I'm not sure what to use, |=
generally has slightly nicer behaviour in the corner cases.
If you have multiple replacements to do, you can pipe them together:
jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'
will update both the "name" and "lname" fields everywhere, and output the whole updated object once.
A few other approaches that may work:
You could also be really explicit about what you're selecting with
(..|objects|select(has("name"))).name |= "XXXX"`
which finds everything, then just the objects, then just the objects that have a "name", then the name field on those objects, and performs the same update as before.
- If you're running the development version of jq (unlikely) then the
walk
function can also do the job:walk(.name?="XXXX")
. All the other versions will work on the latest released version, 1.5.
An alternative multi-update could be
jq '(..|has("name")?) += {name: "XXXX", lname: "1234"}'
which finds everything with a name and then sets both "name" and "lname" on each object using arithmetic update-assignment
*=
and the merging behaviour that+
has for objects.
edited Oct 20 '18 at 7:30
answered Oct 20 '18 at 7:07
Michael HomerMichael Homer
46.7k8123161
46.7k8123161
add a comment |
add a comment |
alternatively, jtc
based solution:
bash $ jtc -w'<name>l+0' -u'"XXX"' your.json
{
"contact": [
{
"id": 111,
"name": "XXX"
}
],
"email": "xxx",
"group": [
{
"lname": "YYY",
"name": "XXX"
}
],
"lname": "YYY",
"name": "XXX",
"pass": "yyy"
}
bash $
add a comment |
alternatively, jtc
based solution:
bash $ jtc -w'<name>l+0' -u'"XXX"' your.json
{
"contact": [
{
"id": 111,
"name": "XXX"
}
],
"email": "xxx",
"group": [
{
"lname": "YYY",
"name": "XXX"
}
],
"lname": "YYY",
"name": "XXX",
"pass": "yyy"
}
bash $
add a comment |
alternatively, jtc
based solution:
bash $ jtc -w'<name>l+0' -u'"XXX"' your.json
{
"contact": [
{
"id": 111,
"name": "XXX"
}
],
"email": "xxx",
"group": [
{
"lname": "YYY",
"name": "XXX"
}
],
"lname": "YYY",
"name": "XXX",
"pass": "yyy"
}
bash $
alternatively, jtc
based solution:
bash $ jtc -w'<name>l+0' -u'"XXX"' your.json
{
"contact": [
{
"id": 111,
"name": "XXX"
}
],
"email": "xxx",
"group": [
{
"lname": "YYY",
"name": "XXX"
}
],
"lname": "YYY",
"name": "XXX",
"pass": "yyy"
}
bash $
answered Jan 9 at 18:23
Dmitry L.Dmitry L.
112
112
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f476536%2fhow-to-find-and-replace-multiple-field-values-using-jq%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown