J.C.
J.C.

Reputation: 13

Parsing JSON to array using jq - bash

I have JSON looking like that:

[
  {
    "file": "aaa.txt",
    "destination": 1
  },
  {
    "file": "bbb.txt",
    "destination": 2
  },
  {
    "file": "ccc.txt",
    "destination": 3
  },
  {
    "file": "ddd.txt",
    "destination": 4
  },
  {
    "file": "eee.txt",
    "destination": 9
  }
]

I'm trying to build a script in bash using command jq to get the number of items in JSON and use the vaules of file, destination in second command. To achieve the first one I use

count=$(curl 'http://mypage/json' | jq length)

I'm getting the number (count) of this elements (5 in this case). Next I want to build while loop from 5 to 1 to put file value into (nomen omen) file (script in the loop should create file called [destination] with [file] as content (example: for firstone file should by called 1 with aaa.txt as a content). And... this is my question - how can I put my JSON into array (or something)? I tried to use

arr=$(curl 'http://mypage/json' | jq'.[]')

but it puts whole json as one. Can you help me please?

Upvotes: 1

Views: 194

Answers (1)

peak
peak

Reputation: 116870

There are several reasonable approaches to solving the problem using jq, but all have in common that jq is only called once. Since bash is one of the tags, then provided the "destination" file names are legal, you could do worse than:

while IFS= read -r destination; do
    IFS= read -r file
    printf "%s" "$file" > "$destination"
done < <(jq -r '.[] | .destination,.file' input.json )

However, this also assumes that the contents of the fields do not contain "newline" or NUL characters. If either might contain literal newlines, then see below.

Also, it would almost surely be better to check the validity of the filenames and/or to handle errors arising from failed attempts to write to the specified filenames. See for example What characters are forbidden in Windows and Linux directory names?

Handling newlines

Assuming the key values do not contain NUL characters:

while IFS= read -r -d '' destination; do
    IFS= read -r -d '' file
    printf "%s" "$file" > "$destination"
done < <(jq -rj '.[] | map_values(tostring+"\u0000") | .destination,.file' input.json )

Upvotes: 5

Related Questions