Unixでjqを使用してテーブルレコードをJSONファイルに変換する

Unixでjqを使用してテーブルレコードをJSONファイルに変換する

多くのレコードを含むLinuxシステムにテーブルがあります。以下を取得するためにクエリを実行しています。

select * from TABNAME_XYZ


CID CN    XY     NAT   UIC    DATE        Region
12  2123  120.9  29.0  100.0  2018-06-08  JAIPUR
13  0987  78.9   100.3 28.8   2020-12-09  DELHI

出力をJSONに変換するシェルスクリプトを作成したいのですが、どこから始めるべきか、何をすべきかわかりません。 JSONは次のようになります。

{"CID":"12","CN":"2123","DATA":{"XY":120.9,"NAT":29.0,"UIC":100.0,"Date":"2018-06-08","REGION":"JAIPUR"}},
{"CID":"13","CN":"0987","DATA":{"XY":78.9,"NAT":100.3,"UIC":28.8,"Date":"2020-12-09","REGION":"DELHI"}}

jqすでに私のシステムにいます。

答え1

フィールドが常に指定された順序であり、入力の最初の行にヘッダー行があり、複数のスペース文字がフィールドを区切ると仮定すると、圧縮された連続スペースを使用してを使用してデータtrを解析できますjq

database-client-command |
tr -s ' ' |
jq -c -Rn '
        input  | split(" ") as $head |
        inputs | split(" ") |
                to_entries |
                        map(.key = $head[.key]) |
                        [ .[:2][], { key: "DATA", value: (.[2:] | from_entries) } ] |
                from_entries'

この式は別の行からjq生データを読み込みます。tr

最初の行はヘッダーに分割され、配列に格納されます$head

ヘッダーで行ったように、残りの行を配列に分割します。フィルタは各配列を「入力型」(キー付きto_entriesオブジェクトの集合)に変換し、数値配列インデックスをキーインヘッダーに置き換えます。keyvaluemap()$head

その後、map()フィルタは配列を並べ替えて、3番目の要素を別の子オブジェクトにDATA移動し、「アイテムフォーム」から再変換します。

キーとデータが再配置されると、from_entriesフィルタは「入力フォーム」から配列を返します。

スクリプトの出力は一連のJSONオブジェクトになり、質問にデータが与えられると、これらのオブジェクトは次のようになります。

{"CID":"12","CN":"2123","DATA":{"XY":"120.9","NAT":"29.0","UIC":"100.0","DATE":"2018-06-08","Region":"JAIPUR"}}
{"CID":"13","CN":"0987","DATA":{"XY":"78.9","NAT":"100.3","UIC":"28.8","DATE":"2020-12-09","Region":"DELHI"}}

RegionREGION変更するには、データベースの照会中または後処理ステップでこれを実行することをお勧めしますDATEDate

最初の行の末尾のコンマのため、期待される結果は有効なJSONではありません。

答え2

実際にDATEと に変換したくない(もしそうする場合、変更するタグを選択するロジックを説明すれば簡単な調整である)、最後に(もう一度言うが、そうしないと簡単な調整です)そして、すべてのUnixシステムのすべてのシェルでawkを使用してください。DateRegionREGION,

$ cat tst.awk
NR==1 {
    split($0,tags)
    next
}
{
    printf "%s{%s,%s,\"DATA\":{", sep, fmt(1), fmt(2)
    for (i=3; i<=NF; i++) {
        printf "%s%s", fmt(i), (i<NF ? "," : "}}")
    }
    sep = ",\n"
}
END {
    print ""
}
function fmt(fldNr,     tag, val) {
    tag = tags[fldNr]
    val = $fldNr
    gsub(/"/,"\\\"",val)
    return sprintf("\"%s\":\"%s\"", tag, val)
}

$ awk -f tst.awk file
{"CID":"12","CN":"2123","DATA":{"XY":"120.9","NAT":"29.0","UIC":"100.0","DATE":"2018-06-08","Region":"JAIPUR"}},
{"CID":"13","CN":"0987","DATA":{"XY":"78.9","NAT":"100.3","UIC":"28.8","DATE":"2020-12-09","Region":"DELHI"}}

答え3

これは一つの方法です。以下を次のように保存しますfoo.awk

{
  if(NR==1){
    for(i=1;i<=NF;i++){
      head[i]=$i
    }
  }
  else{
    printf "{\"%s\":\"%s\",\"%s\":\"%s\",\"DATA\":{\"%s\":%s,\"%s\":%s,\"%s\":%s,\"%s\":\"%s\",\"%s\":\"%s\"}}\n", head[1],$1,head[2],$2,head[3],$3,head[4],$4,head[5],$5,head[6],$6,head[7],$7;

  }
}

それから:

$ cat file |  awk -f foo.awk
{"CID":"12","CN":"2123","DATA":{"XY":120.9,"NAT":29.0,"UIC":100.0,"DATE":"2018-06-08","Region":"JAIPUR"}}
{"CID":"13","CN":"0987","DATA":{"XY":78.9,"NAT":100.3,"UIC":28.8,"DATE":"2020-12-09","Region":"DELHI"}}

ここでは、コマンドの出力をselectファイルに保存しましたfile。あなたの場合は、データベース内のコマンドラインクライアントを使用できます。たとえば、mySQLを使用すると、次のようになります。

mysql -e 'select * from TABNAME_XYZ' | awk -f foo.awk

関連情報