How to format bash array as JSON array
I have a bash array
X=("hello world" "goodnight moon")
What i want to turn into json array
["hello world", "goodnight moon"]
Is there a good way to turn this into a json array of strings without skewing 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 '.'
You can do it:
X=("hello world" "goodnight moon")
printf '%s\n' "${X[@]}" | jq -R . | jq -s .
Output
[
"hello world",
"goodnight moon"
]
It...
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[@]}"
... gives:
["hello world", "goodnight moon", "say \"boo\"", "foo\\bar"]
If you plan on doing this a lot (as you are not encouraged to use a hint), then something like this that does not depend on any subprocess will most likely be useful to you.
You can use:
X=("hello world" "goodnight moon")
sed 's/^/[/; s/,$/]/' <(printf '"%s",' "${X[@]}") | jq -s '.'
[
[
"hello world",
"goodnight moon"
]
]
If the values ββdo not contain ASCII control characters, which must 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
If you're ok with a few extra backslashes, bash is helpful printf "%q"
:
X=("hello world" "goodnight moon" 'say "boo"' 'foo\bar')
json="[$(printf '"%q",' "${X[@]}")"
json="${json%,}]"
echo "$json"
["hello\ world","goodnight\ moon","say\ \"boo\"","foo\\bar"]
Relatively OK for backslashes: node.js has no problem with them:
$ node
> x = ["hello\ world","goodnight\ moon","say\ \"boo\"","foo\\bar"]
[ 'hello world',
'goodnight moon',
'say "boo"',
'foo\\bar' ]