如何使用jq将JSON字符串格式化为表?
刚从Bash脚本开始,偶然发现jq使用JSON 我需要将下面这样的JSON字符串转换为一个表,以便在终端中输出如何使用jq将JSON字符串格式化为表?,json,bash,jq,Json,Bash,Jq,刚从Bash脚本开始,偶然发现jq使用JSON 我需要将下面这样的JSON字符串转换为一个表,以便在终端中输出 [{ "name": "George", "id": 12, "email": "george@domain.com" }, { "name": "Jack", "id": 18, "email": "jack@domain.com" }, { "name": "Joe", "id": 19, "email": "
[{
"name": "George",
"id": 12,
"email": "george@domain.com"
}, {
"name": "Jack",
"id": 18,
"email": "jack@domain.com"
}, {
"name": "Joe",
"id": 19,
"email": "joe@domain.com"
}]
要在终端中显示的内容:
ID Name
=================
12 George
18 Jack
19 Joe
请注意,我不想为每一行显示email属性,因此jq命令应该包含一些过滤。下面是一个简单的姓名和id列表:
list=$(echo "$data" | jq -r '.[] | .name, .id')
printf "$list"
问题是,我不能像表格一样显示它。我知道jq有一些格式化选项,但没有使用printf
时的选项好。我想我想把这些值放在一个数组中,然后我可以自己循环来做格式化。。。?我尝试过的事情给了我不同的结果,但从来都不是我真正想要的
有人能给我指出正确的方向吗?为什么不能像这样:
echo '[{
"name": "George",
"id": 12,
"email": "george@domain.com"
}, {
"name": "Jack",
"id": 18,
"email": "jack@domain.com"
}, {
"name": "Joe",
"id": 19,
"email": "joe@domain.com"
}]' | jq -r '.[] | "\(.id)\t\(.name)"'
输出
12 George
18 Jack
19 Joe
编辑1:对于细粒度格式,请使用
awk等工具
echo '[{
"name": "George",
"id": 12,
"email": "george@domain.com"
}, {
"name": "Jack",
"id": 18,
"email": "jack@domain.com"
}, {
"name": "Joe",
"id": 19,
"email": "joe@domain.com"
}]' | jq -r '.[] | [.id, .name] | @csv' | awk -v FS="," 'BEGIN{print "ID\tName";print "============"}{printf "%s\t%s%s",$1,$2,ORS}'
ID Name
============
12 "George"
18 "Jack"
19 "Joe"
编辑2:回复
我不可能直接得到一个包含数组的变量
来自jq
为什么不呢
一个有点复杂的示例(实际上是从您的示例中修改过来的)将电子邮件更改为数组来演示这一点
echo '[{
"name": "George",
"id": 20,
"email": [ "george@domain1.com" , "george@domain2.com" ]
}, {
"name": "Jack",
"id": 18,
"email": [ "jack@domain3.com" , "jack@domain5.com" ]
}, {
"name": "Joe",
"id": 19,
"email": [ "joe@domain.com" ]
}]' | jq -r '.[] | .email'
输出
[
"george@domain1.com",
"george@domain2.com"
]
[
"jack@domain3.com",
"jack@domain5.com"
]
[
"joe@domain.com"
]
name value
==========
name1 value1
name2 value2
key1 key2
---- ----
V1.1 V2.1
V2.2 V1.2
如果值不包含空格,这可能会有帮助:
read -r -a data <<<'name1 value1 name2 value2'
echo "name value"
echo "=========="
for ((i=0; i<${#data[@]}; i+=2)); do
echo ${data[$i]} ${data[$((i+1))]}
done
使用@tsv
过滤器有很多可取之处,主要是因为它以标准方式处理大量“边缘情况”:
.[] | [.id, .name] | @tsv
添加标题的方法如下:
jq -r '["ID","NAME"], ["--","------"], (.[] | [.id, .name]) | @tsv'
结果是:
ID NAME
-- ------
12 George
18 Jack
19 Joe
length*“-”
要自动生成划线,请执行以下操作:
jq -r '(["ID","NAME"] | (., map(length*"-"))), (.[] | [.id, .name]) | @tsv'
手工定义标题是次优的!省略标题也是次优的
TL;博士
数据
剧本
如何运行
输出:
state statuscode type blockprice created spotinstancerequestid
closed instance-terminated-by-user t3.nano 0.002000 2019-02-24T15:21:36.000Z sir-r5bh7skq
cancelled bad-parameters t3.nano 0.002000 2019-02-24T14:51:47.000Z sir-1k9s5h3m
closed instance-terminated-by-user t3.nano 0.002000 2019-02-24T14:55:26.000Z sir-43x16b6n
cancelled bad-parameters t3.nano 0.002000 2019-02-24T14:29:23.000Z sir-2jsh5brn
active fulfilled t3.nano 0.002000 2019-02-24T15:37:26.000Z sir-z1e9591m
cancelled bad-parameters t3.nano 0.002000 2019-02-24T14:33:42.000Z sir-n7c15y5p
输入:
$ cat /tmp/ins
{
"SpotInstanceRequests": [
{
"Status": {
"Message": "2019-02-24T15:29:38+0000 : 2019-02-24T15:29:38+0000 : Spot Instance terminated due to user-initiated termination.",
"Code": "instance-terminated-by-user",
"UpdateTime": "2019-02-24T15:31:03.000Z"
},
"ActualBlockHourlyPrice": "0.002000",
"ValidUntil": "2019-03-03T15:21:36.000Z",
"InstanceInterruptionBehavior": "terminate",
"Tags": [],
"InstanceId": "i-0414083bef5e91d94",
"BlockDurationMinutes": 60,
"SpotInstanceRequestId": "sir-r5bh7skq",
"State": "closed",
"ProductDescription": "Linux/UNIX",
"LaunchedAvailabilityZone": "eu-north-1a",
"LaunchSpecification": {
"Placement": {
"Tenancy": "default",
"AvailabilityZone": "eu-north-1a"
},
"ImageId": "ami-6d27a913",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"VirtualName": "root",
"NoDevice": "",
"Ebs": {
"Encrypted": false,
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"EbsOptimized": false,
"SecurityGroups": [
{
"GroupName": "default"
}
],
"Monitoring": {
"Enabled": false
},
"InstanceType": "t3.nano",
"AddressingType": "public",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"Description": "eth-zero",
"NetworkInterfaceId": "",
"DeleteOnTermination": true,
"SubnetId": "subnet-420ffc2b",
"AssociatePublicIpAddress": true
}
]
},
"Type": "one-time",
"CreateTime": "2019-02-24T15:21:36.000Z",
"SpotPrice": "0.008000"
},
{
"Status": {
"Message": "Your Spot request failed due to bad parameters.",
"Code": "bad-parameters",
"UpdateTime": "2019-02-24T14:51:48.000Z"
},
"ActualBlockHourlyPrice": "0.002000",
"ValidUntil": "2019-03-03T14:51:47.000Z",
"InstanceInterruptionBehavior": "terminate",
"Tags": [],
"Fault": {
"Message": "Invalid device name /dev/sda",
"Code": "InvalidBlockDeviceMapping"
},
"BlockDurationMinutes": 60,
"SpotInstanceRequestId": "sir-1k9s5h3m",
"State": "cancelled",
"ProductDescription": "Linux/UNIX",
"LaunchedAvailabilityZone": "eu-north-1a",
"LaunchSpecification": {
"Placement": {
"Tenancy": "default",
"AvailabilityZone": "eu-north-1a"
},
"ImageId": "ami-6d27a913",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda",
"VirtualName": "root",
"NoDevice": "",
"Ebs": {
"Encrypted": false,
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"EbsOptimized": false,
"SecurityGroups": [
{
"GroupName": "default"
}
],
"Monitoring": {
"Enabled": false
},
"InstanceType": "t3.nano",
"AddressingType": "public",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"Description": "eth-zero",
"NetworkInterfaceId": "",
"DeleteOnTermination": true,
"SubnetId": "subnet-420ffc2b",
"AssociatePublicIpAddress": true
}
]
},
"Type": "one-time",
"CreateTime": "2019-02-24T14:51:47.000Z",
"SpotPrice": "0.011600"
},
{
"Status": {
"Message": "2019-02-24T15:02:17+0000 : 2019-02-24T15:02:17+0000 : Spot Instance terminated due to user-initiated termination.",
"Code": "instance-terminated-by-user",
"UpdateTime": "2019-02-24T15:03:34.000Z"
},
"ActualBlockHourlyPrice": "0.002000",
"ValidUntil": "2019-03-03T14:55:26.000Z",
"InstanceInterruptionBehavior": "terminate",
"Tags": [],
"InstanceId": "i-010442ac3cc85ec08",
"BlockDurationMinutes": 60,
"SpotInstanceRequestId": "sir-43x16b6n",
"State": "closed",
"ProductDescription": "Linux/UNIX",
"LaunchedAvailabilityZone": "eu-north-1a",
"LaunchSpecification": {
"Placement": {
"Tenancy": "default",
"AvailabilityZone": "eu-north-1a"
},
"ImageId": "ami-6d27a913",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"VirtualName": "root",
"NoDevice": "",
"Ebs": {
"Encrypted": false,
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"EbsOptimized": false,
"SecurityGroups": [
{
"GroupName": "default"
}
],
"Monitoring": {
"Enabled": false
},
"InstanceType": "t3.nano",
"AddressingType": "public",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"Description": "eth-zero",
"NetworkInterfaceId": "",
"DeleteOnTermination": true,
"SubnetId": "subnet-420ffc2b",
"AssociatePublicIpAddress": true
}
]
},
"Type": "one-time",
"CreateTime": "2019-02-24T14:55:26.000Z",
"SpotPrice": "0.011600"
},
{
"Status": {
"Message": "Your Spot request failed due to bad parameters.",
"Code": "bad-parameters",
"UpdateTime": "2019-02-24T14:29:24.000Z"
},
"ActualBlockHourlyPrice": "0.002000",
"ValidUntil": "2019-03-03T14:29:23.000Z",
"InstanceInterruptionBehavior": "terminate",
"Tags": [],
"Fault": {
"Message": "Addressing type must be 'public'",
"Code": "InvalidParameterCombination"
},
"BlockDurationMinutes": 60,
"SpotInstanceRequestId": "sir-2jsh5brn",
"State": "cancelled",
"ProductDescription": "Linux/UNIX",
"LaunchedAvailabilityZone": "eu-north-1a",
"LaunchSpecification": {
"Placement": {
"Tenancy": "default",
"AvailabilityZone": "eu-north-1a"
},
"ImageId": "ami-6d27a913",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda",
"VirtualName": "root",
"NoDevice": "",
"Ebs": {
"Encrypted": false,
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"EbsOptimized": false,
"SecurityGroups": [
{
"GroupName": "default"
}
],
"Monitoring": {
"Enabled": false
},
"InstanceType": "t3.nano",
"AddressingType": "",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"Description": "eth-zero",
"NetworkInterfaceId": "",
"DeleteOnTermination": true,
"SubnetId": "subnet-420ffc2b",
"AssociatePublicIpAddress": true
}
]
},
"Type": "one-time",
"CreateTime": "2019-02-24T14:29:23.000Z",
"SpotPrice": "0.011600"
},
{
"Status": {
"Message": "Your spot request is fulfilled.",
"Code": "fulfilled",
"UpdateTime": "2019-02-24T15:37:28.000Z"
},
"ActualBlockHourlyPrice": "0.002000",
"ValidUntil": "2019-03-03T15:37:26.000Z",
"InstanceInterruptionBehavior": "terminate",
"Tags": [],
"InstanceId": "i-0a29e9de6d59d433f",
"BlockDurationMinutes": 60,
"SpotInstanceRequestId": "sir-z1e9591m",
"State": "active",
"ProductDescription": "Linux/UNIX",
"LaunchedAvailabilityZone": "eu-north-1a",
"LaunchSpecification": {
"Placement": {
"Tenancy": "default",
"AvailabilityZone": "eu-north-1a"
},
"ImageId": "ami-6d27a913",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"VirtualName": "root",
"NoDevice": "",
"Ebs": {
"Encrypted": false,
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"EbsOptimized": false,
"SecurityGroups": [
{
"GroupName": "default"
}
],
"Monitoring": {
"Enabled": false
},
"InstanceType": "t3.nano",
"AddressingType": "public",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"Description": "eth-zero",
"NetworkInterfaceId": "",
"DeleteOnTermination": true,
"SubnetId": "subnet-420ffc2b",
"AssociatePublicIpAddress": true
}
]
},
"Type": "one-time",
"CreateTime": "2019-02-24T15:37:26.000Z",
"SpotPrice": "0.008000"
},
{
"Status": {
"Message": "Your Spot request failed due to bad parameters.",
"Code": "bad-parameters",
"UpdateTime": "2019-02-24T14:33:43.000Z"
},
"ActualBlockHourlyPrice": "0.002000",
"ValidUntil": "2019-03-03T14:33:42.000Z",
"InstanceInterruptionBehavior": "terminate",
"Tags": [],
"Fault": {
"Message": "Invalid device name /dev/sda",
"Code": "InvalidBlockDeviceMapping"
},
"BlockDurationMinutes": 60,
"SpotInstanceRequestId": "sir-n7c15y5p",
"State": "cancelled",
"ProductDescription": "Linux/UNIX",
"LaunchedAvailabilityZone": "eu-north-1a",
"LaunchSpecification": {
"Placement": {
"Tenancy": "default",
"AvailabilityZone": "eu-north-1a"
},
"ImageId": "ami-6d27a913",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda",
"VirtualName": "root",
"NoDevice": "",
"Ebs": {
"Encrypted": false,
"DeleteOnTermination": true,
"VolumeType": "gp2",
"VolumeSize": 8
}
}
],
"EbsOptimized": false,
"SecurityGroups": [
{
"GroupName": "default"
}
],
"Monitoring": {
"Enabled": false
},
"InstanceType": "t3.nano",
"AddressingType": "public",
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"Description": "eth-zero",
"NetworkInterfaceId": "",
"DeleteOnTermination": true,
"SubnetId": "subnet-420ffc2b",
"AssociatePublicIpAddress": true
}
]
},
"Type": "one-time",
"CreateTime": "2019-02-24T14:33:42.000Z",
"SpotPrice": "0.011600"
}
]
}
以上答案的问题是,只有当字段宽度都差不多时,它们才起作用
为了避免此问题,可以使用Linux列
命令:
//input.json
[
{
“姓名”:“乔治”,
“id”:“一个很长的字段”,
“电子邮件”:george@domain.com"
},
{
“姓名”:“杰克”,
“id”:18,
“电子邮件”:jack@domain.com"
},
{
“姓名”:“乔”,
“id”:19,
“电子邮件”:joe@domain.com"
}
]
然后:
我把所有的反应都混合在一起,得到所有这些行为
- 创建标题表
- 处理长字段
- 创建一个要重用的函数
函数bash
function jsonArrayToTable(){
jq -r '(.[0] | ([keys[] | .] |(., map(length*"-")))), (.[] | ([keys[] as $k | .[$k]])) | @tsv' | column -t -s $'\t'
}
样本使用
echo '[{"key1":"V1.1", "key2":"V2.1"}, {"keyA":"V1.2", "key2":"V2.2"}]' | jsonArrayToTable
输出
[
"george@domain1.com",
"george@domain2.com"
]
[
"jack@domain3.com",
"jack@domain5.com"
]
[
"joe@domain.com"
]
name value
==========
name1 value1
name2 value2
key1 key2
---- ----
V1.1 V2.1
V2.2 V1.2
你能为你的jq-r…
命令添加一些示例输出吗?你可以避免使用echo
,jq-r'…'这是你的问题:我有一个字符串“name1 value1 name2 value2 name3 value3”
我怎样才能将它打印成表格?谢谢你的回答。这在这种特殊情况下非常有效,id的长度都相同。想象一下,如果我切换字段的顺序,会得到一个看起来根本不像一张方便的桌子的东西。我真的在寻找一个可以在更多数据集上使用的解决方案。不过,谢谢你的回答!好的,明白了。我不可能直接从jq得到一个包含数组的变量?我总是必须从字符串开始?感谢您的帮助,输出完全符合我的要求(除了名称周围的引号)。从字符串开始,而不是像在Python中那样获得一个随时可用的数组,这感觉很奇怪。对我来说,这感觉既笨拙又肮脏,但我想只有我自己才能适应bash的理念?我将尝试将其变成一个可以重用的函数,这样我就可以使用它来处理更多具有不同标题的JSON字符串。@Rein:对于细粒度格式,您需要以csv格式打印输出,然后使用awk
,但请注意,复杂的情况可能会失败。关于你的第二条评论,请参阅上一次编辑,并与答案一起阅读。谢谢你的链接和解释,非常有用!我开始意识到我不能直接从jq获得阵列,对吗?所以方法是从中获取一个字符串(以一种可行的格式)并从那里开始?甚至在jq的基本过滤器手册页面上都有@tsv过滤器,嗯。。。我想知道我还遗漏了什么:)column-t
巧妙地将标题与表本身对齐。谢谢您可以使用column-ts$'\t'
拆分制表符,但不能拆分空格,否则带空格的值将拆分为多列。从…起
echo '[{"key1":"V1.1", "key2":"V2.1"}, {"keyA":"V1.2", "key2":"V2.2"}]' | jsonArrayToTable
key1 key2
---- ----
V1.1 V2.1
V2.2 V1.2