【问题标题】:Bash sqlite3 -line | How to convert to JSON formatBash sqlite3 -line |如何转换为 JSON 格式
【发布时间】:2016-07-03 01:56:18
【问题描述】:

我想将我的 sqlite 数据从我的数据库转换为 JSON 格式。

我想使用这个语法:

sqlite3 -line members.db "SELECT * FROM members LIMIT 3" > members.txt

输出:

      id = 1
   fname = Leif
   gname = Håkansson
genderid = 1

      id = 2
   fname = Yvonne
   gname = Bergman
genderid = 2

      id = 3
   fname = Roger
   gname = Sjöberg
genderid = 1

如何在 for 循环中使用漂亮的结构化代码来做到这一点? (仅在 Bash 中)

我尝试了一些 awk 和 grep,但还没有取得很大的成功。

如果有一些提示会很好。

我想要类似这样的结果:

[
  {
    "id":1,
    "fname":"Leif",
    "gname":"Hakansson",
    "genderid":1
  },
  {
    "id":2,
    "fname":"Yvonne",
    "gname":"Bergman",
    "genderid":2
  },
  {
    "id":3,
    "fname":"Roger",
    "gname":"Sjberg",
    "genderid":1
  }
}

【问题讨论】:

标签: json bash awk sqlite grep


【解决方案1】:

如果您的 sqlite3 是使用 json1 扩展名编译的(或者如果您可以获得带有 json1 扩展名的 sqlite3 版本),那么您可以使用它来生成 JSON 对象(每行一个 JSON 对象)。例如:

select json_object('id', id, 'fname', fname, 'gname', gname, 'genderid', genderid) ...

然后您可以使用jq 等工具将对象流转换为对象数组,例如将 sqlite3 的输出通过管道传输到 jq -s .

(一个不那么烦人的替代方法可能是使用 sqlite3 函数 json_array(),它会生成一个数组,您可以使用 jq 将其重新组装成一个对象。)

如果 json1 扩展不可用,那么您可以使用以下内容作为起点:

awk 'BEGIN { print "["; } 
 function out() {if (n++) {print ","}; if (line) {print "{" line "}"}; line="";}
 function trim(x) { sub(/^ */, "", x); sub(/ *$/, "", x); return x; }
 NF==0 { out(); next}; 
 {if (line) {line = line ", " }
  i=index($0,"="); 
  line = line "\"" trim(substr($0,1,i-1)) ": \"" substr($0, i+2) "\""}
 END {out(); print "]"} '

或者,您可以使用以下 jq 脚本,它将出现在“=”的 RHS 上的数字字符串转换为数字:

  def trim: sub("^ *"; "") | sub(" *$"; "");
  def keyvalue: index("=") as $i 
    | {(.[0:$i] | trim): (.[$i+2:] | (tonumber? // .))};
  [foreach (inputs, "") as $line ({object: false, seed: {} };
     if ($line|trim) == "" then { object: .seed, seed : {} }
     else {object: false, 
           seed: (.seed + ($line | keyvalue)) }
     end;
     .object | if . and (. != {}) then . else empty end ) ]

【讨论】:

  • 感谢您的帮助!
【解决方案2】:

我想我更愿意用每条记录一行来解析 sqlite 输出,而不是你建议的 sqlite3 -line 非常冗长的输出格式。所以,我会选择这个:

sqlite3 members.db "SELECT * FROM members LIMIT 3"

这让我可以解析:

1|Leif|Hakansson|1
2|Yvonne|Bergman|2
3|Roger|Sjoberg|1

如果我将输入分隔符设置为|,我现在可以使用awk 解析它

awk -F '|'

并使用以下内容在每行中选取 4 个字段并将它们保存在一个数组中,如下所示:

{ id[++i]=$1; fname[i]=$2; gname[i]=$3; genderid[i]=$4 }

那么我需要做的就是在最后打印出你需要的输出格式。但是,您的输出中有双引号,在 awk 中引用它们很痛苦,所以我暂时使用另一个管道符号 (|) 作为双引号,然后在最后得到 tr用双引号替换所有管道符号 - 只是为了让代码更容易看。所以整个解决方案是这样的:

sqlite3 members.db "SELECT * FROM members LIMIT 3" | awk -F'|' '
   # sqlite output line - pick up fields and store in arrays
   { id[++i]=$1; fname[i]=$2; gname[i]=$3; genderid[i]=$4 }

   END {
      printf "[\n";
      for(j=1;j<=i;j++){
         printf "  {\n"
         printf "    |id|:%d,\n",id[j]
         printf "    |fname|:|%s|,\n",fname[j]
         printf "    |gname|:|%s|,\n",gname[j]
         printf "    |genderid|:%d\n",genderid[j]
         closing="  },\n"
         if(j==i){closing="  }\n"}
         printf closing;
      }
      printf "]\n";
   }' | tr '|' '"'

【讨论】:

  • 感谢大家的帮助!
  • 很高兴。祝你的项目好运!
【解决方案3】:

只需使用 SQLite 3.33.0 或更高版本输入 -json 参数并获取 json 输出:

$ sqlite3 -json database.db "select * from TABLE_NAME"

来自 SQLite 版本 3.33.0 注意:

...

  1. CLI 增强功能:
  • 添加了四种新的输出模式:“box”、“json”、“markdown”和“table”。
  • “列”输出模式会自动扩展列以包含最长的输出行,并自动打开“.header”(如果有) 之前没有设置。
  • “引用”输出模式支持“.separator”
  • CLI 内置了十进制扩展名和 ieee754 扩展名

...

【讨论】:

    【解决方案4】:

    Sqlite-utils 完全符合您的要求。默认情况下,输出将为 JSON。

    【讨论】:

      【解决方案5】:

      迟到总比不插好。

      将 sqlite3 保存到文本文件。

      获取jo(jo 在发行版存储库中也可用)

      并使用这个 bash 脚本。

      while read line
      do 
          id=`echo $line | cut -d"|" -f1`
          fname=`echo $line | cut -d"|" -f2`
          gname=`echo $line | cut -d"|" -f3`
          genderid=`echo $line | cut -d"|" -f4`
          jsonline=`jo id="$id" fname="$fname" gname="$gname" genderid="$genderid"`
          json="$json $jsonline"
      done < "$1"
      
      jo -a $json
      

      【讨论】:

        【解决方案6】:

        请不要使用awk 创建(或解析)json。为此有专门的工具。像xidel这样的工具。
        虽然首先是 html、xml 和 json 解析器,但xidel 也可以解析纯文本。

        我想使用这个工具提供一个非常优雅的解决方案(代码比jq 少得多)。
        我会假设你的'members.txt'

        首先创建每个json对象的序列:

        xidel -s members.txt --xquery 'tokenize($raw,"\n\n")'
        

        或者……

        xidel -s members.txt --xquery 'tokenize($raw,"\n\n") ! (position(),.)'
        1
              id = 1
           fname = Leif
           gname = Håkansson
        genderid = 1
        2
              id = 2
           fname = Yvonne
           gname = Bergman
        genderid = 2
        3
              id = 3
           fname = Roger
           gname = Sjöberg
        genderid = 1
        

        ...为了更好地向您展示序列中的各个项目。

        现在你有 3 个多行字符串。要将每个项目/字符串转换为另一个序列,其中每个项目都是一个新行:

        xidel -s members.txt --xquery 'tokenize($raw,"\n\n") ! x:lines(.)'
        

        x:lines(.)tokenize(.,'\r\n?|\n') 的简写)

        现在对“=”(创建另一个序列)上的每一行进行标记并将其保存到变量中。例如第一行这个序列是("id","1"),第二行是("fname","Leif"),等等:

        xidel -s members.txt --xquery 'tokenize($raw,"\n\n") ! (for $x in x:lines(.) let $a:=tokenize($x," = ") return ($a[1],$a[2]))'
        

        最后删除前导空格(normalize-space()),创建一个 json 对象({| {key-value-pair} |})并将所有 json 对象放入一个数组中([ ... ]):

        xidel -s members.txt --xquery '[tokenize($raw,"\n\n") ! {|for $x in x:lines(.) let $a:=tokenize($x," = ") return {normalize-space($a[1]):$a[2]}|}]'
        

        美化+输出:

        xidel -s members.txt --xquery '
          [
            tokenize($raw,"\n\n") ! {|
              for $x in x:lines(.)
              let $a:=tokenize($x," = ")
              return {
                normalize-space($a[1]):$a[2]
              }
            |}
          ]
        '
        [
          {
            "id": "1",
            "fname": "Leif",
            "gname": "Håkansson",
            "genderid": "1"
          },
          {
            "id": "2",
            "fname": "Yvonne",
            "gname": "Bergman",
            "genderid": "2"
          },
          {
            "id": "3",
            "fname": "Roger",
            "gname": "Sjöberg",
            "genderid": "1"
          }
        ]
        

        注意:对于xidel-0.9.9.7173 和更新的--json-mode=deprecated,需要使用[ ] 创建一个json 数组。创建 json 数组的新(XQuery 3.1)方法是使用array{}

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-08-30
          • 2012-06-20
          • 2019-11-12
          • 2016-06-12
          • 2021-10-06
          • 2022-09-01
          • 1970-01-01
          相关资源
          最近更新 更多