I’ve got a JSON list (the value of a key-value pair containing a list of items):
[ "john", "boris", "joe", "frank" ]
How would I convert this to a bash array, so I can iterate over them?
Advertisement
Answer
Easy Case: Newline-Free Strings
The simple approach is to use jq
to transform your list into a line-per-item, and read that into your script:
json='[ "john", "boris", "joe", "frank" ]' readarray -t your_array < <(jq -r '.[]' <<<"$json") declare -p your_array
…properly emits:
declare -a your_array=([0]="john" [1]="boris" [2]="joe" [3]="frank")
Tricky Case: Strings With Newlines
Sometimes you need to read strings that can contain newlines (or want to avoid security risks caused by malicious or malformed data being read into the wrong fields). To avoid that, you can use NUL delimiters between your data (and remove any NUL values contained therein):
json='[ "johnndoe", "marconquent", "maliciousu0000data" ]' array=( ) while IFS= read -r -d '' item; do array+=( "$item" ) done < <(jq -j '.[] | ((. | sub("u0000"; "<NUL>")) + "u0000")' <<<"$json") declare -p array
…properly emits:
declare -a array=([0]=$'johnndoe' [1]=$'marconquent' [2]="malicious<NUL>data")
…and printf '<%s>nn' "${array[@]}"
properly emits:
<john doe> <marco quent> <malicious<NUL>data>
(Note that very new bash has readarray -0
, which can avoid the need for the while IFS= read -r -d ''
loop given above, but that’s not common yet. Also note that you can use that loop to directly iterate over content from jq
, avoiding the need to store content in an array in the first place; see BashFAQ #1).