将平面JSON转换为具有列标题的TSV文件



我正在将一些带有JQ的JSON重新格式化为TSV文件。我只能用值创建一个TSV,但我不知道如何将键值作为列标题包含在一行中?

样本输入:

{
"id":"1234",
"host":"6789",
"proto":"UDP",
"location":"Boston",
"timestamp":"2020-12-01T14:18:45.717Z",
"src_ip":"192.168.3.70",
"dest_ip":"8.8.8.8",
"dest_port":53,
"message":"Some Information",
"severity":1,
"details":"Some Details",
"categories":["a","b","c"]
}

期望输出:

"locationttimestamptsrc_iptdest_iptdest_port"
"Bostont2020-12-01T15:13:16.242Zt10.8.25.63t10.8.1.3t445"
"Atlantat2020-12-01T15:11:15.929Zt10.8.25.63t10.80.1.3t445"
"Chicagot2020-12-01T15:09:45.271Zt10.34.196.12t10.8.1.3t445"

这句话让我很接近:

cat input.json | jq  '. | to_entries 
| map(select(.key=="timestamp"), select(.key=="location"), select(.key=="src_ip"), select(.key=="dest_ip"), select(.key=="dest_port"))
| map(.key), map(.value) 
| @tsv'

但是标题行在输出中重复:

"locationttimestamptsrc_iptdest_iptdest_port"
"Bostont2020-12-01T15:13:16.242Zt10.8.25.63t10.8.1.3t445"
"locationttimestamptsrc_iptdest_iptdest_port"
"Atlantat2020-12-01T15:11:15.929Zt10.8.25.63t10.80.1.3t445"

有没有办法只打印第一行的键,然后只打印其余行的值,只使用JQ?

使用@tsv函数将这种平面对象JSON转换为TSV格式的一种方法是执行

jq -n ' ["location", "timestamp", "src_ip", "dest_ip", "dest_port"] as $hdr | 
$hdr, ( inputs | [ .[ $hdr[] ] ] ) | @tsv'

这是有效的,通过重用标头中的键字段,.[ $hdr[] ]是一个简单的技巧,可以将hdr数组中每个文本字段的值扩展到对象中相应的值(请参见通用对象索引(。通过将其括在括号中,可以获得数组中选定的字段值。收集此数组和头数组后,应用@tsv函数来获得表格形式。

jq播放片段-演示