towi
towi

Reputation: 22307

generate JSON out of command line arguments

I want to create JSON output with jq that looks like this:

{
  "records": [
    {
      "id": "1234",
      "song": "Yesterday",
      "artist": "The Beatles"
    }
  ]
}

I assumed I have to twiddle with the "filter" of jq whose concept I don't fully get after reading the doc.

This is what I got so far:

$ jq --arg id 1234 \
     --arg song Yesterday \
     --arg artist "The Beatles" \
  '.' \
  <<<'{ "records" : [{ "id":"$id", "song":"$song", "artist":"$artist" }] }'

which prints

{
  "records": [
    {
      "id" : "$id",
      "song" : "$song",
      "artist" : "$artist"
    }
  ]
}

Do I modify the filter? Do I change the input?

Upvotes: 3

Views: 709

Answers (6)

Artem Klevtsov
Artem Klevtsov

Reputation: 9423

jo can build arrays and nested objects:

$ jo -p records[]="$(jo id=12345 song=Yesterday artist='The Beatles')"
{
   "records": [
      {
         "id": 12345,
         "song": "Yesterday",
         "artist": "The Beatles"
      }
   ]
}

Upvotes: 0

Philippe
Philippe

Reputation: 26697

jq  --null-input\
    --argjson id     1234\
    --arg     song   Yesterday\
    --arg     artist "The Beatles"\
    '{ "records" : [{ $id, $song, $artist }] }'

gives

{
  "records": [
    {
      "id": 1234,
      "song": "Yesterday",
      "artist": "The Beatles"
    }
  ]
}

Upvotes: 2

Inian
Inian

Reputation: 85780

An alternate way to your original attempt, on jq-1.6 you can use the $ARGS.positional attribute to construct your JSON from scratch

jq -n '
  $ARGS.positional | { 
    records: [ 
      { 
        id:     .[0], 
        song:   .[1], 
        artist: .[2]   
      }
    ] 
  }' --args 1234 Yesterday "The Beatles" 

As for why your original attempt didn't work, looks you are not modifying your json at all, with your filter '.' you are basically just reading in and printing out "untouched". The arguments set using --arg need to be set to the object inside the filter.

Upvotes: 8

oguz ismail
oguz ismail

Reputation: 50785

You are looking for something like this:

jq --null-input               \
   --arg id 1234              \
   --arg song Yesterday       \
   --arg artist "The Beatles" \
'.records[0] = {$id, $song, $artist}'

Each variable reference between curly brackets is converted to a key-value pair where its name is the key, and its value is the value. And assigning the resulting object to .records[0] forces the creation of the surrounding structure.

Upvotes: 7

Poshi
Poshi

Reputation: 5762

Start with an empty JSON and add the missing bits:

$ jq --arg id 1234 \
     --arg song Yesterday \
     --arg artist "The Beatles" \
     '. | .records[0].id=$id | .records[0].song=$song | .records[0].artist=$artist' \
  <<<'{}'

Outputs

{
  "records": [
    {
      "id": "1234",
      "song": "Yesterday",
      "artist": "The Beatles"
    }
  ]
}

Another, cleaner, approach based on the answer of @Inian could be

jq -n \
   --arg id 1234
   --arg song Yesterday
   --arg artist "The Beatles"
   '{records: [{id:$id, song:$song, artist:$artist}]}'

Upvotes: 1

customcommander
customcommander

Reputation: 18921

I think you got the JSON/JQ the wrong way round:

This should be your JQ script:

rec.jq

{
  records: [
    {
      id: $id,
      song: $song,
      artist: $artist
    }
  ]
}

And this should be your JSON (empty):

rec.json

{}

Then:

jq --arg id 123 --arg song "Yesterday" --arg artist "The Beatles" -f rec.jq rec.json

Which produces:

{
  "records": [
    {
      "id": "123",
      "song": "Yesterday",
      "artist": "The Beatles"
    }
  ]
}

Upvotes: 1

Related Questions