How to format a bash array as a JSON array
Solution 1
You can do this:
X=("hello world" "goodnight moon")
printf '%s\n' "${X[@]}" | jq -R . | jq -s .
output
[
"hello world",
"goodnight moon"
]
Solution 2
This ...
X=("hello world" "goodnight moon" 'say "boo"' 'foo\bar')
json_array() {
echo -n '['
while [ $# -gt 0 ]; do
x=${1//\\/\\\\}
echo -n \"${x//\"/\\\"}\"
[ $# -gt 1 ] && echo -n ', '
shift
done
echo ']'
}
json_array "${X[@]}"
... yields:
["hello world", "goodnight moon", "say \"boo\"", "foo\\bar"]
If you are planning to do a lot of this (as your reluctance to use a subshell suggests) then something such as this that does not rely on any subprocess is likely to your advantage.
Solution 3
Since jq 1.6 you can do this:
jq --compact-output --null-input '$ARGS.positional' --args "${X[@]}"
giving:
["hello world","goodnight moon"]
This has the benefit that no escaping is required at all. It handles strings containing newlines, tabs, double quotes, backslashes and other control characters. (Well, it doesn't handle NUL characters but you can't have them in a bash array in the first place.)
Solution 4
You can use:
X=("hello world" "goodnight moon")
sed 's/^/[/; s/,$/]/' <(printf '"%s",' "${X[@]}") | jq -s '.'
[
[
"hello world",
"goodnight moon"
]
]
Solution 5
If the values do not contain ASCII control characters, which have to be escaped in strings in valid JSON, you can also use sed
:
$ X=("hello world" "goodnight moon")
$ printf %s\\n "${X[@]}"|sed 's/["\]/\\&/g;s/.*/"&"/;1s/^/[/;$s/$/]/;$!s/$/,/'
["hello world",
"goodnight moon"]
If the values contain ASCII control characters, you can do something like this:
X=($'a\ta' $'a\n\\\"')
for((i=0;i<${#X[@]};i++));do
[ $i = 0 ]&&printf \[
printf \"
e=${X[i]}
e=${e//\\/\\\\}
e=${e//\"/\\\"}
for((j=0;j<${#e};j++));do
c=${e:j:1}
if [[ $c = [[:cntrl:]] ]];then
printf '\\u%04x' "'$c"
else
printf %s "$c"
fi
done
printf \"
if((i<=${#X[@]}-2));then
printf ,
else
printf \]
fi
done
Jon
01000011 01100001 01101100 01101100 00100000 01101101 01100101 00100000 01101010 01100001 01101110 01100100 01100101 01110010 01110011
Updated on June 07, 2022Comments
-
Jon almost 2 years
I have a bash array
X=("hello world" "goodnight moon")
That I want to turn into a json array
["hello world", "goodnight moon"]
Is there a good way for me to turn this into a json array of strings without looping over the keys in a subshell?
(for x in "${X[@]}"; do; echo $x | sed 's|.*|"&"|'; done) | jq -s '.'
This clearly doesn't work
echo "${X[@]}" | jq -s -R '.'