65

Here is my config.json:

{
    "env": "dev",
    "dev": {
        "projects" : {
            "prj1": {
                "dependencies": {},
                "description": ""
            }
        }
    }
}

Here are my bash commands:

PRJNAME='prj1'

echo $PRJNAME

jq --arg v "$PRJNAME" '.dev.projects."$v"' config.json 
jq '.dev.projects.prj1' config.json 

The output:

prj1
null
{
  "dependencies": {},
  "description": ""
}

So $PRJNAME is prj1, but the first invocation only outputs null.

Can someone help me?

peak
  • 105,803
  • 17
  • 152
  • 177
lisi4ok
  • 725
  • 1
  • 6
  • 9
  • 1
    Have you tried removing the `"` around `$v`? Why aren't you using the shell to fill in the variable like `jq ".dev.projects.$PRJNAME" config.json`? – Rambo Ramon Jan 12 '16 at 14:46
  • @RamboRamon, using the shell to fill in the variable is error-prone -- think about if it contains characters like quotes that need to be escaped. `jq` is guaranteed to generate syntactically valid output. – Charles Duffy Jan 12 '16 at 17:45

5 Answers5

97

The jq program .dev.projects."$v" in your example will literally try to find a key named "$v". Try the following instead:

jq --arg v "$PRJNAME" '.dev.projects[$v]' config.json 
  • What if i want to pass 2 or more params ? Can you show me the example ? – lisi4ok Jan 12 '16 at 15:32
  • 17
    You can pass more than one argument by using the `--arg` instruction several times, as in: `jq --arg foo 1 --arg bar 2 -n '[$foo, $bar]'` –  Jan 12 '16 at 15:58
  • 1
    Is it possible to pass multiple components in the arg? eg `PRJNAME='.dev.projects.prj1' jq --arg v "$PRJNAME" '[$v]' config.json `. Certainly that code doesn't work - it converts the arg to a string surrounded by square brackets, so I'm guessing that it doesn't like the dot notation... – lane Jan 17 '18 at 10:38
  • 2
    remove the '' from [$v] – datacruncher Mar 15 '19 at 15:55
34

You can use --argjson too when you make your json.

--arg a v       # set variable $a to value <v>;
--argjson a v   # set variable $a to JSON value <v>;
Gryu
  • 2,102
  • 2
  • 16
  • 29
Sebastien DIAZ
  • 351
  • 3
  • 2
  • 14
    You need to use `argjson` when passing a number or boolean which you don't want wrapped in quotes. – Tom Sep 14 '18 at 10:32
18

As asked in a comment above there's a way to pass multiple argumets. Maybe there's a more elegant way, but it works.

  • If you are sure always all keys needed you can use this:
jq --arg key1 $k1 --arg key2 $k2 --arg key3 $k3 --arg key4 $k4 '.[$key1] | .[$key2] | .[$key3] | .[$key4] '

  • If the key isn't always used you could do it like this:
jq --arg key $k ' if key != "" then .[$key] else . end'

  • If key sometimes refers to an array:
jq --arg key $k ' if type == "array" then .[$key |tonumber] else .[$key] end'

of course you can combine these!

LuWa
  • 191
  • 2
  • 8
5

you can do this:


    key="dev.projects.prj1"
    filter=".$key"
    cat config.json | jq $filter

Z.San
  • 51
  • 1
  • 1
0

My example bash command to replace an array in a json file. Everything is in variables:

a=/opt/terminal/conf/config.json ; \
b='["alchohol"]' ; \
c=terminal.canceledInspections.resultSendReasons ; \
cat $a | jq .$c ; \
cat $a | jq --argjson b $b --arg c $c 'getpath($c / ".") = $b' | sponge $a ; \
cat $a | jq .$c