【问题标题】:How to format a bash array as a JSON array如何将 bash 数组格式化为 JSON 数组
【发布时间】:2015-01-04 16:39:28
【问题描述】:

我有一个 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 '.'

【问题讨论】:

    标签: arrays json bash jq


    【解决方案1】:

    作为answer的改进

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

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案2】:

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

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

    给予:

    ["hello world","goodnight moon"]
    

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

    【讨论】:

      【解决方案3】:

      如果值不包含 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
      

      【讨论】:

        【解决方案4】:

        如果你对一些额外的反斜杠没意见,bash 的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"]
        

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

        $ node
        > x = ["hello\ world","goodnight\ moon","say\ \"boo\"","foo\\bar"]
        [ 'hello world',
          'goodnight moon',
          'say "boo"',
          'foo\\bar' ]
        

        【讨论】:

        • 很好地使用了printf,但如果我正确阅读了JSON specs,那么实际上额外的反斜杠不是好吧。
        【解决方案5】:

        你可以这样做:

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

        输出

        [
          "hello world",
          "goodnight moon"
        ]
        

        【讨论】:

        • 精神上+1 和+10:唯一安全和正确的答案。要同时处理嵌入式换行符,for f in "${X[@]}"; do printf '%s' "$f" | jq -R -s .; done | jq -s .
        • 这会将一个空数组转换为[ "" ]
        • @JanGassen 在我的实验中,只有在 X 未声明为数组时才会发生这种情况。
        【解决方案6】:

        这...

        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[@]}"
        

        ...产量:

        ["hello world", "goodnight moon", "say \"boo\"", "foo\\bar"]
        

        如果您打算做很多这样的事情(正如您不愿使用子外壳所暗示的那样),那么诸如此类不依赖于任何子进程的事情可能对您有利。

        【讨论】:

        • 请注意,不依赖子进程的属性取决于echo作为shell内置实现,bash就是这样。
        • 如果是 bash,你应该使用原生 [[ and ]] 而不是 [ and ]。
        • 你似乎搞混了,@DennisV.R..[ 是标准实用程序,有时也可以作为内置的 shell 使用(参见 pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html)。 [[ ... ]] 是特定于 bash 的。因此,我在这个答案中选择前者而不是后者,以获得更大的便携性。但也请注意,问题确实 指定bash,特别是通过标题、文本和标签。
        • 我想注意的是,bash 中的 [[ 作为本机部分的性能更好,但 [ 作为外部实用程序更适合兼容性,正如你所说。
        • 这里可能存在的问题是,如果数组包含控制字符(例如换行符、制表符、换页符),则无法正确转义它们,并且 JSON 不允许它们未转义。
        【解决方案7】:

        你可以使用:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-07-30
          • 2018-12-28
          • 1970-01-01
          • 2019-08-06
          • 2020-11-22
          • 2014-12-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多