I want to modify a JSON file by using the Linux command line.
I tried these steps:
[root@localhost]# INPUT="dsa"
[root@localhost]# echo $INPUT
dsa
[root@localhost]# CONF_FILE=test.json
[root@localhost]# echo $CONF_FILE
test.json
[root@localhost]# cat $CONF_FILE
{
"global" : {
"name" : "asd",
"id" : 1
}
}
[root@localhost]# jq -r '.global.name |= '""$INPUT"" $CONF_FILE > tmp.$$.json && mv tmp.$$.json $CONF_FILE
jq: error: dsa/0 is not defined at <top-level>, line 1:
.global.name |= dsa
jq: 1 compile error
Desired output:
[root@localhost]# cat $CONF_FILE
{ "global" : {
"name" : "dsa",
"id" : 1 } }
Your only problem was that the script passed to jq
was quoted incorrectly.
In your particular case, using a single double-quoted string with embedded \
-escaped "
instances is probably simplest:
jq -r ".global.name = \"$INPUT\"" "$CONF_FILE" > tmp.$$.json && mv tmp.$$.json "$CONF_FILE"
Generally, however, chepner's helpful answer shows a more robust alternative to embedding the shell variable reference directly in the script: Using the --arg
option to pass a value as a jq
variable allows single-quoting the script, which is preferable, because it avoids confusion over what elements are expanded by the shell up front and obviates the need for escaping $
instances that should be passed through to jq
.
Also:
=
is sufficient to assign the value; while |=
, the so-called update operator, works too, it behaves the same as =
in this instance, because the RHS is a literal, not an expression referencing the LHS - see the manual.As for why your quoting didn't work:
'.global.name |= '""$INPUT""
is composed of the following tokens:
.global.name |=
(due to single-quoting)""
- i.e., the empty string - the quotes will be removed by the shell before jq
sees the script$INPUT
(which makes its value subject to word-splitting and globbing).""
.With your sample value, jq
ended up seeing the following string as its script:
.global.name |= dsa
As you can see, the double quotes are missing, causing jq
to interpret dsa
as a function name rather than a string literal, and since no argument was passed to (non-existent) function dsa
, jq
's error message referenced it as dsa/0
- a function with no (0
) arguments.
It's much simpler and safer to pass the value using the --arg
option:
jq -r --arg newname "$INPUT" '.global.name |= $newname' "$CONF_FILE"
This ensures that the exact value of $INPUT
is used and quoted as a JSON value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With