arraysjsonbasheditjq

Convert bash array to json array and insert to file using jq


Given a bash array, how to convert it to a JSON array in order to output to a file with jq?

Additionnally: is there a way to keep the server_nohup array unchanged instead of re-writing the whole json file each time?

newArray=(100 200 300)
jq -n --arg newArray $newArray '{
    client_nohup: [ 
        $newArray
    ],
    server_nohup: [

    ]
}' > $projectDir/.watch.json

Current output:

{
"client_nohup": [
    "100"
],
"server_nohup": []
}

Desired output:

{
"client_nohup": [
    100,
    200,
    300
],
"server_nohup": []
}

Solution

  • Given a bash array, how to convert it to a JSON array

    Assuming your jq supports the --args command-line option, you can use it in conjunction with the built-in $ARGS pseudo-variable, as illustrated by this example:

    $ declare -a output=($'abc\ndef' "x y z")
    $ jq -c -n '$ARGS.positional' --args "${output[@]}"
    ["abc\ndef","x y z"]
    

    Here, all the values of the bash array are converted to JSON strings. Notice that the embedded new-line in the first value of the bash array is correctly handled.

    Additionally ...

    (1) If all the values in newArray are valid as JSON values without spaces, then you could get away with piping the values as a stream, e.g.

    newArray=(100 200 300)
    echo "${newArray[@]}" |
      jq -s '{client_nohup: ., server_nohup: []}'
    

    (2) Now let's suppose you merely wish to update the "nohup" object in a file, say nohup.json:

    { "client_nohup": [], "server_nohup": [ "keep me" ] }
    

    Since you are using bash, you can then write:

    echo "${newArray[@]}" |
      jq -s --argjson nohup "$(cat nohup.json)" '
        . as $newArray | $nohup | .client_nohup = $newArray
      '
    

    Output

    (1)

    {
      "client_nohup": [
        100,
        200,
        300
       ],
      "server_nohup": []
    }
    

    (2)

    {
      "client_nohup": [
        100,
        200,
        300
      ],
      "server_nohup": [
        "keep me"
      ]
    }
    

    Other cases

    Where there's a will, there's a jq way :-)

    See for example the accepted answer at How to format a bash array as a JSON array (though this is not a completely generic solution).

    Further thoughts

    You might wish to convert numeric strings to JSON numbers, e.g. using the jq idiom: (tonumber? // .).

    You might also wish to exploit the fact that bash strings cannot contain NUL characters.