2

I have a JSON file like this:

{
 "name" : "Allow",
 "source" : [ "*" ,"0.0.0.0"]
}

I need to parse this JSON so the array of strings inside JSON can convert to "space separated string". I later need to supply these variables to another function like this:

local file="file-name"
while read val; do
    local name
    local source

    name=$(jq --raw-output '.name' <<< ${val})
    source=$(jq --raw-output '.source' <<< ${val})
__test "${name}" "${source}" 
  done < <(cat ${file} | jq -rc '.[]')

So,I basically need to change source to a string and pass it, rather than a list of strings.

4
  • 4
    Not sure what you're asking here (in particular, why you are using a shell loop to process the file line-by-line) - but jq has a built in function for joining elements of an array jq -r '.source | join(" ")' and also a built in TSV filter jq -r '.source | @tsv' Commented Jun 23, 2021 at 21:03
  • Basically, what I am asking here is that source should have "* 0.0.0.0" and not "*","0.0.0.0". It should be passed as one string Commented Jun 23, 2021 at 21:06
  • Please put your expected output from the example into your question. There's clearly some confusion over what you mean by "space separated string" Commented Jun 24, 2021 at 7:11
  • When asking a question like this one typically enter A) a usable input sample including various scenarios. B) A desired output sample (manually modified) C) What one have tried and where one are stuck. It is very important to specify clearly what the end-result should be - and add information to question by edit, not in comments.
    – ibuprofen
    Commented Jun 24, 2021 at 7:16

1 Answer 1

2

In general, the elements of an array may be converted to a single space-delimited string using join(" ") in jq. In your case, the .source array may be converted into a space-delimited string using .source | join(" ").

I'm assuming that your input document contains an array of objects of the type that you show in the question.

Instead of calling jq multiple times in each iteration, consider using jq to get the data into a form that is usable as a single stream:

jq -r '.[] | [ .name, (.source | join(" ")) ] | @tsv' file.json |
while IFS=$'\t' read -r name source; do
    __test "$name" "$source"
done

This provides two tab-delimited fields to the loop. The first field is simply the .name value from the JSON document, while the second field is a space-delimited string made by concatenating the elements from the .source array. The concatenation of array elements into a singe string is done with join() in jq, and the tab-delimited output is produced by providing @tsv with an array.


If you feel brave, you could even use

eval "$( jq -r '.[] | [ "__test", .name, (.source | join(" ")) ] | @sh' file.json )"

This uses jq to actually create the shell commands that you aim to execute. The calling shell then gets this script as a string and runs it with eval. In the jq expression, @sh is used to provide proper quoting for the command name and its arguments. The jq expression here expects an array of objects of the type shown in the question.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .