简体   繁体   中英

Assigning an Array Parsed With jq to Bash Script Array

I parsed a json file with jq like this :

# cat test.json | jq '.logs' | jq '.[]' | jq '._id' | jq -s

It returns an array like this : [34,235,436,546,.....]

Using bash script i described an array :

# declare -a msgIds = ...

This array uses () instead of [] so when I pass the array given above to this array it won't work.

([324,32,45..]) this causes problem. If i remove the jq -s , an array forms with only 1 member in it.

Is there a way to solve this issue?

We can solve this problem by two ways. They are:

Input string:

// test.json
{
    "keys": ["key1","key2","key3"]
}

Approach 1:

1) Use jq -r (output raw strings, not JSON texts) .

KEYS=$(jq -r '.keys' test.json)
echo $KEYS
# Output: [ "key1", "key2", "key3" ]

2) Use @sh (Converts input string to a series of space-separated strings). It removes square brackets[], comma(,) from the string.

KEYS=$(<test.json jq -r '.keys | @sh')
echo $KEYS
# Output: 'key1' 'key2' 'key3'

3) Using tr to remove single quotes from the string output. To delete specific characters use the -d option in tr .

KEYS=$((<test.json jq -r '.keys | @sh')| tr -d \') 
echo $KEYS
# Output: key1 key2 key3

4) We can convert the comma-separated string to the array by placing our string output in a round bracket(). It also called compound Assignment, where we declare the array with a bunch of values.

ARRAYNAME=(value1 value2  .... valueN)
#!/bin/bash
KEYS=($((<test.json jq -r '.keys | @sh') | tr -d \'\"))

echo "Array size: " ${#KEYS[@]}
echo "Array elements: "${KEYS[@]}

# Output: 
# Array size:  3
# Array elements: key1 key2 key3

Approach 2:

1) Use jq -r to get the string output, then use tr to delete characters like square brackets, double quotes and comma.

#!/bin/bash
KEYS=$(jq -r '.keys' test.json  | tr -d '[],"')
echo $KEYS

# Output: key1 key2 key3

2) Then we can convert the comma-separated string to the array by placing our string output in a round bracket().

#!/bin/bash
KEYS=($(jq -r '.keys' test.json  | tr -d '[]," '))

echo "Array size: " ${#KEYS[@]}
echo "Array elements: "${KEYS[@]}

# Output:
# Array size:  3
# Array elements: key1 key2 key3

Use jq -r to output a string "raw", without JSON formatting, and use the @sh formatter to format your results as a string for shell consumption. Per the jq docs:

@sh:

The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings.

So can do eg

msgids=($(<test.json jq -r '.logs[]._id | @sh'))

and get the result you want.

From the jq FAQ ( https://github.com/stedolan/jq/wiki/FAQ ):

𝑸: How can a stream of JSON texts produced by jq be converted into a bash array of corresponding values?

A: One option would be to use mapfile (aka readarray), for example:

mapfile -t array <<< $(jq -c '.[]' input.json)

An alternative that might be indicative of what to do in other shells is to use read -r within a while loop. The following bash script populates an array, x, with JSON texts. The key points are the use of the -c option, and the use of the bash idiom while read -r value; do ... done < <(jq .......) while read -r value; do ... done < <(jq .......) :

#!/bin/bash
x=()
while read -r value
do
  x+=("$value")
done < <(jq -c '.[]' input.json)

++ To resolve this, we can use a very simple approach:

++ Since I am not aware of you input file, I am creating a file input.json with the following contents:

input.json:

{
    "keys": ["key1","key2","key3"]
}

++ Use jq to get the value from the above file input.json:

Command: cat input.json | jq -r '.keys | @sh' cat input.json | jq -r '.keys | @sh'

Output: 'key1' 'key2' 'key3'

Explanation: | @sh removes [ and "

++ To remove ' ' as well we use tr

command: cat input.json | jq -r '.keys | @sh' | tr -d \\' cat input.json | jq -r '.keys | @sh' | tr -d \\'

Explanation: use tr delete -d to remove '

++ To store this in a bash array we use () with `` and print it:

command:

KEYS=(`cat input.json | jq -r '.keys | @sh' | tr -d \'`)

To print all the entries of the array: echo "${KEYS[*]}"

To correctly parse values that have spaces, newlines (or any other arbitrary characters) just use jq's @sh filter and bash's declare -a .

json='{"data":["A B", "C\nD", ""]}'
str=$(jq -r '.data | @sh' <<<"$json")
declare -a arr="($str)"    # must be quoted like this
$ declare -p arr
declare -a arr=([0]="A B" [1]=$'C\nD' [2]="")

The reason that this works correctly is that @sh will produce a space-separated list of shell-quoted words:

$ echo "$str"
'A B' 'C
D' ''

and this is exactly the format that declare expects for an array definition. No need for a while read loop or any other pre-processing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM