Passing variable to jq to edit a json file

I am trying to pass a variable into jq like this '.Linux.date.$var' so far I have tried quoting them by name which is working fine. But I want to use variable to call them.

I have this, which is working fine

exectime=$(date -d now);    
cp $check_exec_history $check_exec_history.tmp
    jq --arg key1 true --arg key2 "$exectime" --arg name "$name" '.Linux.script_executed.first = $key1 | .Linux.date_executed.first = $key2' $check_exec_history.tmp > $check_exec_history; 
    rm $check_exec_history.tmp;

I want to get to this, but not working:

name=first;
exectime=$(date -d now);
cp $check_exec_history $check_exec_history.tmp
jq --arg key1 true --arg key2 "$exectime" --arg name "$name" ".Linux.script_executed.$name = $key1 | .Linux.date_executed.$name = $key2" $check_exec_history.tmp > $check_exec_history; 
rm $check_exec_history.tmp;

I came this far: using this answer https://stackoverflow.com/q/40027395/9496100 But I am not sure where I am doing mistake.

name=first;
exectime=$(date -d now);    
cp $check_exec_history $check_exec_history.tmp
    jq --arg key1 true --arg key2 "$exectime" --arg name "$name" '.Linux.script_executed.name==$name = $key1 | .Linux.date_executed.name==$name = $key2' $check_exec_history.tmp > $check_exec_history; rm $check_exec_history.tmp;

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

You can use square bracket indexing on all objects in jq, so [$name] works for what you’re trying:

jq --arg key1 true --arg name "$name" '.Linux.script_executed[$name] = $key1 ...' 

This use of square brackets is not very well documented in the manual, which makes it look like you can only use .[xyz], but ["x"] works anywhere that .x would have as long as it’s not right at the start of an expression (that is, .a.x and .a["x"] are the same, but ["x"] is an array construction).

Note the use of single quotes above – that is so Bash won’t try to interpret $name and $key1 as shell variables. You should keep the double quotes for --arg name "$name", because that really is a shell variable, and it should be quoted to make it safe to use.

Solution 2

Michael Homer has the correct response. I’ll post what I was aiming for in relation to op’s question.

I am trying to modify a permissions graph obtained through a REST API curl call using jq to output a json file which I will PUT to the server with updates. The following is the output of the curl API query:

{
  "revision": 2,
  "groups": {
    "1": {
      "1": {
        "native": "none",
        "schemas": "none"
      },
      "2": {
        "native": "write",
        "schemas": "all"
      }
    },
    "2": {
      "1": {
        "native": "write",
        "schemas": "all"
      },
      "2": {
        "native": "write",
        "schemas": "all"
      }
    }
  }
}

As you can see it is nested. I am trying to modify this using bash variables every time a new permission set is created and when databases are created. For exmaple I’m trying to modify groups."1"."2"."native" and “schemas” also "groups."2"."2".native and “schemas” values. It’s rough, but the keys are as follows groups.groupPermissionID.DatabaseID.*

In order to modify this nested graph on the fly via a bash shell script, I used Michael Homer’s solution of applying [$name]. In my case I had to do this twice in a row. i.e., [$gID][$dID]. In the following setup the variables are constant but in my model they are command arguments passed to the bash shell script.

dbID="2"
pgroupID="2"

curl -X GET -H "Content-Type: application/json" -H "X-Metabase-Session: XXXXX-XXXXX-XXXXX-XXXXXXXXX" "http://localhost:9000/api/permissions/graph" | jq --arg dID "$dbID"   --arg gID "$pgroupID" -r '.groups."1"[$dID]."native" = "none" | .groups."1" [$dID]."schemas" = "none" | .groups[$gID][$dID]."native" ="none" .groups[$gID][$dID]."schemas" ="none"' > permissiongraph.json

Which produced the following updated JSON graph for me to PUT to my server:

{
  "revision": 2,
  "groups": {
    "1": {
      "1": {
        "native": "none",
        "schemas": "none"
      },
      "2": {
        "native": "none",
        "schemas": "none"
      }
    },
    "2": {
      "1": {
        "native": "write",
        "schemas": "all"
      },
      "2": {
        "native": "none",
        "schemas": "none"
      }
    }
  }
}

Michael is correct when he said this is sparsely documented. I couldn’t find it anywhere in the manuals. I hope this helps someone.

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply