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 '.'

      

+3


source to share


5 answers


You can do it:

X=("hello world" "goodnight moon")
printf '%s\n' "${X[@]}" | jq -R . | jq -s .

      



Output

[
  "hello world",
  "goodnight moon"
]

      

+7


source


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.

+3


source


You can use:

X=("hello world" "goodnight moon")
sed 's/^/[/; s/,$/]/' <(printf '"%s",' "${X[@]}") | jq -s '.'
[
  [
    "hello world",
    "goodnight moon"
  ]
]

      

0


source


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

      

0


source


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' ]

      

-1


source







All Articles