21

我有一个 bash 数组

X=("hello world" "goodnight moon")

我想变成一个json数组

["hello world", "goodnight moon"]

我有没有一种好方法可以将其转换为 json 字符串数组,而无需遍历子外壳中的键?

(for x in "${X[@]}"; do; echo $x | sed 's|.*|"&"|'; done) | jq -s '.'

这显然行不通

echo "${X[@]}" | jq -s -R '.'
4

7 回答 7

40

你可以这样做:

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

输出

[
  "hello world",
  "goodnight moon"
]
于 2014-11-07T20:10:20.893 回答
8

从 jq 1.6 开始,您可以这样做:

jq --compact-output --null-input '$ARGS.positional' --args "${X[@]}"

给予:

["hello world","goodnight moon"]

这样做的好处是根本不需要转义。它处理包含换行符、制表符、双引号、反斜杠和其他控制字符的字符串。(嗯,它不处理 NUL 字符,但你不能将它们放在 bash 数组中。)

于 2021-05-11T14:55:55.820 回答
7

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.

于 2014-11-07T20:07:23.707 回答
1

您可以使用:

X=("hello world" "goodnight moon")
sed 's/^/[/; s/,$/]/' <(printf '"%s",' "${X[@]}") | jq -s '.'
[
  [
    "hello world",
    "goodnight moon"
  ]
]
于 2014-11-07T19:57:17.647 回答
1

如果值不包含 ASCII 控制字符,必须在有效 JSON 中的字符串中进行转义,您还可以使用sed

$ X=("hello world" "goodnight moon")
$ printf %s\\n "${X[@]}"|sed 's/["\]/\\&/g;s/.*/"&"/;1s/^/[/;$s/$/]/;$!s/$/,/'
["hello world",
"goodnight moon"]

如果值包含 ASCII 控制字符,您可以执行以下操作:

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
于 2016-01-03T15:05:40.800 回答
0

如果您可以使用一些额外的反斜杠,那么 bash'sprintf "%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"]

关于反斜杠的 OK-ness:node.js 没有问题:

$ node
> x = ["hello\ world","goodnight\ moon","say\ \"boo\"","foo\\bar"]
[ 'hello world',
  'goodnight moon',
  'say "boo"',
  'foo\\bar' ]
于 2014-11-07T20:12:48.803 回答
0

随着答案的改进

https://stackoverflow.com/a/26809278/16566807

脚本会产生一些在包含时可能有用的格式。脚本符合 BASH 规范,用 shellcheck 检查。

#!/bin/bash
#
#
        X=("hello world" "goodnight moon" 'say "boo"' 'foo\bar')
#
#       set parameter to define purpose: return_format
#               php5    -> for 5.x
#               -> https://stackoverflow.com/questions/7073672/how-to-load-return-array-from-a-php-file/7073686
#               php     -> for 7.x and greater
#               json    -> for $array=@file_get_contents($f); json_decode($array, true);
#               /none/  -> for JS to JSON.Parse(myJSON);
#       function call with array as parameter: return_array "${array[@]}"
        return_array() {
                rf="${return_format}"
                if [[ $rf = "php5" ]]; then
                        q=("<?php return array(" ");")
                elif [[ $rf = "php" ]];then
                        q=("<?php return [" "];")
                elif [[ $rf = "json" ]];then
                        q=("{" "}")
                else
                        q=("[" "]")
                fi
                echo -n "${q[0]}"
                while [[ $# -gt 0 ]]; do
                        x=${1//\\/\\\\}
                        echo -n "\"${x//\"/\\\"}\""
                        [[ $# -gt 1 ]] && echo -n ', '
                        shift
                done
                echo "${q[1]}"
        }

echo "PHP 5.x"
return_format="php5"
return_array "${X[@]}"
echo "PHP 7.x"
return_format="php"
return_array "${X[@]}"
echo "JSON for PHP"
return_format="json"
return_array "${X[@]}"
echo "JSON for JS"
return_format=
return_array "${X[@]}"

将产生输出:

PHP 5.x
<?php return array("hello world", "goodnight moon", "say \"boo\"", "foo\\bar");
PHP 7.x
<?php return ["hello world", "goodnight moon", "say \"boo\"", "foo\\bar"];
JSON for PHP
{"hello world", "goodnight moon", "say \"boo\"", "foo\\bar"}
JSON for JS
["hello world", "goodnight moon", "say \"boo\"", "foo\\bar"]
于 2021-10-15T11:54:22.073 回答