Bash sqlite3 行 |如何转换为JSON格式

问题描述 投票:0回答:6

我想将数据库中的 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
6个回答
15
投票

如果你的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 脚本,它将“=”右侧出现的数字字符串转换为数字:

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

14
投票

只需使用 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 输出,而不是您使用

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

1
投票

Sqlite-utils 正是您所寻找的。默认情况下,输出将为 JSON。


0
投票

迟插总比不插好。

将 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

0
投票

请不要使用

awk
创建(或解析)json。有专门的工具可以做到这一点。像这样的工具。
虽然首先是 html、xml 和 json 解析器,但使用正确的功能
xidel
也可以将纯文本转换为 JSON:

$ xidel -s members.txt -e '
  array{
    for $member in tokenize($raw,"\n\n") return
    map:merge(
      for $entry in x:lines($member)
      let $val:=tokenize($entry," = ")
      return {
        normalize-space($val[1]):$val[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"
  }
]

(

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

的简写
© www.soinside.com 2019 - 2024. All rights reserved.