本文主要讲解在OOS如何对任务中的值进行筛选,任务中值的筛选主要依赖模版中两个常见字段,一个是ValueSelector,另一个是PropertySelector,且这两个字段必须配合jq表达式使用。那么接下来就分别讲下jq是什么,两个筛选字段何时需要定义、在哪定义和作用,以及各场景下jq表达式使用的分析。
jq介绍
jq 是一个开源的数据处理工具,它可处理JSON格式的数据,比如按照您指定的jq表达式,筛选出JSON中你想要的部分。筛选时,jq把JSON格式的数据作为input,并根据指定的jq表达式进行筛选,然后返回一个output。jq有很多灵活的使用方法,详见后附的jq语法手册。
OOS中的筛选字段
先说下OOS任务中值的筛选目的,无非两种,一种是筛出期待的结果,并将其赋值给某个参数,供其他任务使用该参数;另一种则是筛选出期待的结果,在任务中将结果值与预先指定的值进行比较,用来检查某种条件。所以OOS中有两个用来筛选的字段,分别是ValueSelector和PropertySelector,前者用在给参数赋值前,后者用在检查某个条件前。
当任务有具体Outputs时,需要在Outputs中定义ValueSelector字段,该字段用来筛选任务动作返回的值,并且将筛选结果赋值给Outputs输出的参数。具体讲,如任务的动作为API类动作,则动作返回值即任务调用API后返回的JSON值;若任务的动作为事件触发器,则动作返回值为触发器监控事件发生的JSON消息通知体。筛选方式是jq把动作返回值作为输入参数,通过字段的jq表达式进行筛选,筛选结果作为任务的Outputs输出参数值。
当任务的动作为ACS::WaitFor 或ACS::CheckFor时,需要在任务的Properties部分定义PropertySelector字段,
该字段用来筛选任务调用API返回的JSON值,筛选方式是jq把API返回的JSON作为输入参数,并通过字段的jq表达式进行筛选,最后OOS将筛选结果与Properties中的DesiredValues或NotDesiredValues字段内包含的值进行比较,比较结果作为任务等待或判断的参考,进而执行后面的逻辑。
jq在OOS中的使用
ValueSelector
场景1
FormatVersion: OOS-2019-06-01
Description: Adds backend servers by specifying tag.
Parameters:
loadBalancerId:
Description: The ID of the SLB instance.
Type: String
AllowedPattern: lb-[A-Za-z0-9]*
MaxLength: 30
MinLength: 1
tagKey:
Description: The specific tag key.
Type: String
MinLength: 1
tagValue:
Description: The specific tag value.
Type: String
MaxLength: 30
MinLength: 1
OOSAssumeRole:
Description: The RAM role to be assumed by OOS.
Type: String
Default: OOSServiceRole
RamRole: '{{ OOSAssumeRole }}'
Tasks:
- Name: describeRunningInstancesByTag
Action: ACS::ExecuteApi
Description: Views the ECS instances by specifying tag.
Properties:
Service: ECS
API: DescribeInstances
Parameters:
Status: Running
Tags:
- Key: '{{ tagKey }}'
Value: '{{ tagValue }}'
Outputs:
instanceIds:
Type: List
ValueSelector: .Instances.Instance[].InstanceId
我们来看下上面的模版,请直接看Tasks部分的describeRunningInstancesByTag任务,该任务是有具体Outputs的,其定义了输出名称为instanceIds
的参数,参数Type为List,同时也定义了ValueSelector字段,并且该字段的jq表达式为.Instances.Instance[].InstanceId
。
就如Outputs中参数名 instanceIds
字面意思,其表示输出API返回结果中所有ECS实例ID,那么该任务调用的API是DescribeInstances,API返回的JSON结果样例如下。结合此JSON样例,我们看下在.Instances.Instance[].InstanceId
作用下,instanceIds最终返回值的获取过程。首先筛选出JSON中Key为Instances
的结果,然后对结果继续筛选,获取Key为Instance
的结果,该结果是一个数组,此时又对所得结果进行迭代,并将每个迭代结果中Key为InstanceId
的值以List类型进行返回,于是得到最终返回值["id-001","id-002"],即'{{describeRunningInstancesByTag.instanceIds}}'的值为["id-001","id-002"]'。
API调用返回样例(JSON)
{
"PageNumber":"1",
"TotalCount":"1",
"PageSize":"10",
"RequestId":"14A07460-EBE7-47CA-9757-12CC4761D47A",
"Instances":{
"Instance":[
{
"ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
"InnerIpAddress":{
"IpAddress":[
"10.170.XX.XXX"
]
},
"InstanceId":"id-001",
"EipAddress":{},
"InternetMaxBandwidthIn":"-1",
"ZoneId":"cn-shenzhen-a",
"InstanceNetworkType":"classic",
"PublicIpAddress":{
"IpAddress":[
"120.25.XX.XXX"
]
},
"InternetChargeType":"PayByTraffic",
"HostName":"iZ94t3s0j***",
"InstanceType":"ecs.s2.large",
"SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
"IoOptimized":"false",
"CreationTime":"2015-07-27T07:08Z",
"Status":"Running",
"VpcAttributes":{
"PrivateIpAddress":{
"IpAddress":[]
}
},
"InternetMaxBandwidthOut":"1",
"SecurityGroupIds":{
"SecurityGroupId":[
"sg-94kd0c***"
]
},
"RegionId":"cn-shenzhen",
"OperationLocks":{
"LockReason":[]
},
"InstanceChargeType":"PostPaid",
"ExpiredTime":"2011-09-08T16:00Z",
"InstanceName":"FinanceJoshua1"
},
{
"ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
"InnerIpAddress":{
"IpAddress":[
"10.170.XX.XXX"
]
},
"InstanceId":"id-002",
"EipAddress":{},
"InternetMaxBandwidthIn":"-1",
"ZoneId":"cn-shenzhen-a",
"InstanceNetworkType":"classic",
"PublicIpAddress":{
"IpAddress":[
"120.25.XX.XXX"
]
},
"InternetChargeType":"PayByTraffic",
"HostName":"iZ94t3s0j***",
"InstanceType":"ecs.s2.large",
"SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
"IoOptimized":"false",
"CreationTime":"2015-07-27T07:08Z",
"Status":"Running",
"VpcAttributes":{
"PrivateIpAddress":{
"IpAddress":[]
}
},
"InternetMaxBandwidthOut":"1",
"SecurityGroupIds":{
"SecurityGroupId":[
"sg-94kd0c***"
]
},
"RegionId":"cn-shenzhen",
"OperationLocks":{
"LockReason":[]
},
"InstanceChargeType":"PostPaid",
"ExpiredTime":"2011-09-08T16:00Z",
"InstanceName":"FinanceJoshua2"
}
]
}
}
场景2
FormatVersion: OOS-2019-06-01
Description: Resets system disks to its initial state by specifying instance IDs.
The specified ECS instances must be in stopped status.
Parameters:
instanceIds:
Description: The ID list of the ECS instance.
Type: List
maxErrors:
Description: The maximum number of errors allowed during task execution.
Type: Number
Default: 0
concurrency:
Description: Concurrency ratio of task execution.
Type: Number
Default: 1
OOSAssumeRole:
Description: The RAM role to be assumed by OOS.
Type: String
Default: OOSServiceRole
RamRole: '{{ OOSAssumeRole }}'
Tasks:
- Name: checkInstanceReady
Action: ACS::CheckFor
Description: Checks ECS instances is in the stopped status.
Properties:
Service: ECS
API: DescribeInstances
Parameters:
InstanceIds:
- '{{ ACS::TaskLoopItem }}'
DesiredValues:
- Stopped
PropertySelector: Instances.Instance[].Status
Loop:
MaxErrors: '{{ maxErrors }}'
Concurrency: '{{ concurrency }}'
Items: '{{ instanceIds }}'
- Name: querySystemDisks
Action: ACS::ExecuteAPI
Description: Views system disk of the ECS instance.
Properties:
Service: ECS
API: DescribeDisks
Parameters:
InstanceId: '{{ ACS::TaskLoopItem }}'
DiskType: system
Loop:
Items: '{{ instanceIds }}'
Outputs:
diskIds:
AggregateType: Fn::ListJoin
AggregateField: diskId
Outputs:
diskId:
Type: String
ValueSelector: .Disks.Disk[].DiskId
我们来看下上面的模版,请直接看Tasks部分的querySystemDisks任务,该任务是有具体Outputs的,其定义了输出名称为 diskId
的参数,参数Type为 String
,同时也定义了ValueSelector字段,并且该字段的jq表达式为 .Disks.Disk[].DiskId
。
就如Outputs中参数名diskId字面意思,其表示输出API返回结果中的磁盘ID,那么该任务调用的API是DescribeDisks,API返回的JSON结果样例如下。结合此JSON样例,我们看下在 .Disks.Disk[].DiskId 作用下,diskId最终返回值的获取过程。首先筛选出JSON中Key为Disks的结果,然后对结果继续筛选,获取Key为Disk的结果,该结果是一个数组,此时又对所得结果进行迭代,并将每个迭代结果中Key为DiskId的值以String类型进行返回,于是得到最终返回值 'd-28m5zb1sz
',即'{{querySystemDisks.diskId}}'的值为'd-28m5zb1sz
'。
上面可能有疑问,该场景的jq表达式和场景一的类似,且处理的数据结构也一样,为何此处最后只返回了一个String,而不像场景一返回了List。简单解释下,其实返回参数的Type是不同的,当Type为List时,OOS最后会把返回的一个或多个结果装到List中作为最终结果返回;当Type为String时,OOS最后会取返回的一个或多个结果中的第一个来作为最终结果。
API调用返回样例(JSON)
{
"PageNumber":1,
"TotalCount":9,
"PageSize":2,
"RequestId":"ACD9BBB0-A9D1-46D7-9630-B7A69889E110",
"Disks":{
"Disk":[
{
"ImageId":"",
"Description":"",
"Device":"",
"ProductCode":"",
"Portable":true,
"DetachedTime":"2014-07-23T08:28:48Z",
"Type":"data",
"InstanceId":"",
"ZoneId":"cn-qingdao-b",
"EnableAutoSnapshot":false,
"DiskName":"",
"AttachedTime":"2014-07-23T07:47:35Z",
"SourceSnapshotId":"",
"CreationTime":"2014-07-23T02:44:07Z",
"Status":"Available",
"DeleteAutoSnapshot":true,
"Category":"cloud",
"RegionId":"cn-qingdao",
"DeleteWithInstance":false,
"OperationLocks":{
"OperationLock":[]
},
"DiskId":"d-28m5zb1sz",
"Size":5
},
{
"ImageId":"",
"Description":"",
"Device":"",
"ProductCode":"",
"Portable":true,
"DetachedTime":"",
"Type":"data",
"InstanceId":"",
"ZoneId":"cn-qingdao-b",
"EnableAutoSnapshot":false,
"DiskName":"",
"AttachedTime":"",
"SourceSnapshotId":"",
"CreationTime":"2014-07-23T02:44:06Z",
"Status":"Available",
"DeleteAutoSnapshot":true,
"Category":"cloud",
"RegionId":"cn-qingdao",
"DeleteWithInstance":false,
"OperationLocks":{
"OperationLock":[]
},
"DiskId":"d-28zfrmo13",
"Size":5
}
]
}
}
场景3
---
FormatVersion: OOS-2019-06-01
Description: Start ECS instance when instance is stopped.
Parameters:
accessToken:
Description: Dingtalk access_token to be notified.
Type: String
AllowedPattern: '[A-Za-z0-9]*'
regionId:
Description: The Region Id of SLB and Instance.
Type: String
MinLength: 1
MaxLength: 30
OOSAssumeRole:
Description: The RAM role to be assumed by OOS.
Type: String
Default: OOSServiceRole
loadBalancerId:
Description: The ID of the SLB instance.
Type: String
AllowedPattern: lb-[A-Za-z0-9]*
MaxLength: 30
MinLength: 1
RamRole: '{{OOSAssumeRole}}'
Tasks:
- Name: whenInstanceStopped
Action: 'ACS::EventTrigger'
Properties:
Product: ECS
Name:
- 'Instance:StateChange'
Level:
- INFO
Content:
state:
- Stopped
Outputs:
instanceId:
ValueSelector: content.resourceId
Type: String
- Name: checkNeedRemoveOrNot
Action: ACS::CheckFor
Description: check the interrupted Instance is being added on SLB or Not.
OnError: ACS::END
OnSuccess: ACS::NEXT
Properties:
Service: SLB
API: DescribeLoadBalancerAttribute
Parameters:
RegionId: '{{ regionId }}'
LoadBalancerId: '{{ loadBalancerId }}'
DesiredValues:
- "{{whenInstanceStopped.instanceId}}"
PropertySelector: 'BackendServers.BackendServer[].ServerId|select(.=="{{whenInstanceStopped.instanceId}}")'
- Name: queryLoadBalancerAttribute
Action: ACS::ExecuteApi
Description: Views ECS instances to backend servers.
Properties:
Service: SLB
API: DescribeLoadBalancerAttribute
Parameters:
RegionId: '{{ regionId }}'
LoadBalancerId: '{{ loadBalancerId }}'
Outputs:
removeOrNot:
Type: List
ValueSelector: 'BackendServers.BackendServer[]|select(.ServerId=="{{whenInstanceStopped.instanceId}}")'
backendServersToRemove:
Type: List
ValueSelector: 'BackendServers.BackendServer[]|select(.ServerId=="{{whenInstanceStopped.instanceId}}")|del(.Type)'
我们来看下上面的模版,先看Tasks部分的whenInstanceStopped
任务,它会输出一个名为 instanceId
的参数,关于这个任务知道这些就够了。然后看Tasks部分的 queryLoadBalancerAttribute
任务,该任务是有具体Outputs的,比如其定义了输出名称为 backendServersToRemove
的参数,参数Type为 List
,同时也在参数中定义了ValueSelector字段,并且该字段的jq表达式为 .BackendServers.BackendServer[]|
select(.ServerId=="{{whenInstanceStopped.instanceId}}")|del(.Type)
,表达式好长,没关系,我们分析完,您就会发现它很简单。
就如Outputs中参数名backendServersToRemove字面意思,其表示输出API返回结果中的后端服务器列表,那么该任务调用的API是DescribeLoadBalancerAttribute,API返回的JSON结果样例如下。结合此JSON样例,我们看下在这个很长的jq表达式作用下,backendServersToRemove最终返回值的获取过程。首先筛选出JSON中Key为BackendServers
的结果,然后对结果继续筛选,获取Key为BackendServer
的结果,该结果是一个数组,此时对所得结果进行迭代,然后我们看到的管道符 |
,也就是把迭代获取的所有结果交到下一段操作,操作是,将每个迭代结果中Key为ServerId
的值与whenInstanceStopped
任务输出参数instanceId
的值进行比较。如果比较结果是相等,则拿到该ServerId
所在的这个Mapping,并将该Mapping中Key为的Type
的key-val对剔除,再把该Mapping返回;如果比较结果为不相等,则忽略掉这个ServerId
所在的Mapping。比较完后做下整理把所有返回的Mapping放在一个List中返回。假如whenInstanceStopped.instanceId
值是"i-bp1234",得到最终返回值则为 [{"ServerId":"i-bp1234","Weight":100 }]
,即'{{queryLoadBalancerAttribute.backendServersToRemove}}'的值为[{"ServerId":"i-bp1234","Weight":100 }]
。
API调用返回样例(JSON)
{
"CreateTimeStamp":1541679713000,
"RegionIdAlias":"cn-hangzhou",
"HasReservedInfo":"false",
"BackendServers":{
"BackendServer":[
{
"ServerId":"i-bpxccv123456jo7v",
"Weight":100,
"Type":"ecs"
}
]
},
"ListenerPorts":{
"ListenerPort":[]
},
"VSwitchId":"vsw-bp1ccv123456jk9bmlj",
"InternetChargeType":"paybytraffic",
"VpcId":"vpc-bp1ccv123456j1qc5cm",
"SlaveZoneId":"cn-hangzhou-d",
"NetworkType":"vpc",
"LoadBalancerSpec":"slb.s2.small",
"ListenerPortsAndProtocol":{
"ListenerPortAndProtocol":[]
},
"PayType":"PayOnDemand",
"Bandwidth":5120,
"LoadBalancerName":"abc1",
"ResourceGroupId":"rg-acfmxazb4ph6aiy",
"AddressIPVersion":"ipv4",
"LoadBalancerId":"lb-bp23456jfuca5",
"EndTimeStamp":32493801600000,
"MasterZoneId":"cn-hangzhou-b",
"ListenerPortsAndProtocal":{
"ListenerPortAndProtocal":[]
},
"Address":"192.168.0.6",
"RegionId":"cn-hangzhou",
"RequestId":"35D745B3-1567-4855-9EF1-F5CED3C1670C",
"CreateTime":"2018-11-08T12:21:53Z",
"EndTime":"2999-09-08T16:00:00Z",
"AddressType":"intranet",
"LoadBalancerStatus":"active"
}
PropertySelector
场景1(CheckFor)
FormatVersion: OOS-2019-06-01
Description: Creates a disk and attaches a data disk to an ECS instance.
Parameters:
diskName:
Description: The name of the disk.
Type: String
zoneId:
Description: The zone ID that is available in the specified region.
Type: String
diskCategory:
Description: The category of the data disk.
Type: String
instanceId:
Description: Creates a subscription disk and the system automatically attaches
it to a subscription instance with the InstanceId you specified.
Type: String
AllowedPattern: i-[A-Za-z0-9]*
MinLength: 1
MaxLength: 30
size:
Description: The size of the disk.
Type: String
Tasks:
- Name: checkInstanceReady
Action: ACS::CheckFor
Description: Checks whether the ECS instance status is running or stopped.
Properties:
Service: ECS
API: DescribeInstances
Parameters:
InstanceIds:
- '{{ instanceId }}'
DesiredValues:
- Running
- Stopped
PropertySelector: .Instances.Instance[].Status
我们来看下上面的模版,请直接看Tasks部分的checkInstanceReady任务,该任务的动作是 ACS::CheckFor
,其Properties部分定义了DesiredValues的值为 ['Running','Stopped']
,同时也定义了PropertySelector字段,并且该字段的jq表达式为 .Instances.Instance[].Status
。
该任务中,DesiredValues和PropertySelector两个字段会被联合起来,用来验证指定的条件即['Running','Stopped']
,验证过程为先把API返回的JSON结果通过jq表达式筛选处理,再检查处理得到的筛选结果是否在DesiredValues字段的List中。如果在List中,则该任务执行结果为Success,否则该任务执行结果为Failed。
那么该任务调用的API是DescribeInstances,API返回的JSON结果样例如下。结合此JSON样例,我们看下在 .Instances.Instance[].Status
作用下,最终返回值的获取过程。首先筛选出JSON中Key为Instances
的结果,然后对结果继续筛选,获取Key为Instance
的结果,该结果是一个数组,此时对所得结果进行迭代,迭代获取数组中的第一个元素,并将该元素中Key为 Status
的值作为与指定的条件比较的值,即检查'Running'是否在['Running','Stopped']
中。
API调用返回样例(JSON)
{
"PageNumber":"1",
"TotalCount":"1",
"PageSize":"10",
"RequestId":"14A07460-EBE7-47CA-9757-12CC4761D47A",
"Instances":{
"Instance":[
{
"ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
"InnerIpAddress":{
"IpAddress":[
"10.170.XX.XXX"
]
},
"InstanceId":"id-001",
"EipAddress":{},
"InternetMaxBandwidthIn":"-1",
"ZoneId":"cn-shenzhen-a",
"InstanceNetworkType":"classic",
"PublicIpAddress":{
"IpAddress":[
"120.25.XX.XXX"
]
},
"InternetChargeType":"PayByTraffic",
"HostName":"iZ94t3s0j***",
"InstanceType":"ecs.s2.large",
"SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
"IoOptimized":"false",
"CreationTime":"2015-07-27T07:08Z",
"Status":"Running",
"VpcAttributes":{
"PrivateIpAddress":{
"IpAddress":[]
}
},
"InternetMaxBandwidthOut":"1",
"SecurityGroupIds":{
"SecurityGroupId":[
"sg-94kd0c***"
]
},
"RegionId":"cn-shenzhen",
"OperationLocks":{
"LockReason":[]
},
"InstanceChargeType":"PostPaid",
"ExpiredTime":"2011-09-08T16:00Z",
"InstanceName":"FinanceJoshua1"
},
{
"ImageId":"centos6u5_64_20G_aliaegis_20150130.vhd",
"InnerIpAddress":{
"IpAddress":[
"10.170.XX.XXX"
]
},
"InstanceId":"id-002",
"EipAddress":{},
"InternetMaxBandwidthIn":"-1",
"ZoneId":"cn-shenzhen-a",
"InstanceNetworkType":"classic",
"PublicIpAddress":{
"IpAddress":[
"120.25.XX.XXX"
]
},
"InternetChargeType":"PayByTraffic",
"HostName":"iZ94t3s0j***",
"InstanceType":"ecs.s2.large",
"SerialNumber":"51d1353b-22bf-4567-a176-8b3e12e43135",
"IoOptimized":"false",
"CreationTime":"2015-07-27T07:08Z",
"Status":"Running",
"VpcAttributes":{
"PrivateIpAddress":{
"IpAddress":[]
}
},
"InternetMaxBandwidthOut":"1",
"SecurityGroupIds":{
"SecurityGroupId":[
"sg-94kd0c***"
]
},
"RegionId":"cn-shenzhen",
"OperationLocks":{
"LockReason":[]
},
"InstanceChargeType":"PostPaid",
"ExpiredTime":"2011-09-08T16:00Z",
"InstanceName":"FinanceJoshua2"
}
]
}
}
场景2(WaitFor)
FormatVersion: OOS-2019-06-01
Description: Creates a custom image.
Parameters:
imageName:
Description: The image name.
Type: String
instanceId:
Description: The ID of the instance.
Type: String
AllowedPattern: i-[A-Za-z0-9]*
MinLength: 1
MaxLength: 30
Tasks:
- Name: checkInstanceReady
Action: ACS::CheckFor
Description: Checks whether the ECS instance status is running or stopped.
Properties:
Service: ECS
API: DescribeInstances
Parameters:
InstanceIds:
- '{{ instanceId }}'
DesiredValues:
- Running
- Stopped
PropertySelector: Instances.Instance[].Status
- Name: createImage
Action: ACS::ExecuteAPI
Description: Creates a custom image.
Properties:
Service: ECS
API: CreateImage
Parameters:
ImageName: '{{ imageName }}'
InstanceId: '{{ instanceId }}'
Outputs:
imageId:
Type: String
ValueSelector: ImageId
- Name: untilImageReady
Action: ACS::WaitFor
Description: Waits for the image to be available.
Properties:
Service: ECS
API: DescribeImages
Parameters:
ImageId: '{{ createImage.imageId }}'
DesiredValues:
- Available
PropertySelector: .Images.Image[].Status
我们来看下上面的模版,请直接看Tasks部分的untilImageReady任务,该任务的动作是 ACS::WaitFor
,其Properties部分定义了DesiredValues的值为 ['Available']
,同时也定义了PropertySelector字段,并且该字段的jq表达式为 .Images.Image[].Status
。
该任务中,DesiredValues和PropertySelector两个字段会被联合起来,用来验证指定的条件即['Available']
,验证过程为先把API返回的JSON结果通过jq表达式筛选处理,再检查处理得到的筛选结果是否在DesiredValues字段的List中。如果在List中,则该任务不再继续等待,并结束该任务向下执行;否则该任务会隔段时间再次调用API,并检查结果是否满足条件,直至条件满足或超出最大检查次数。
那么该任务调用的API是DescribeImages,API返回的JSON结果样例如下。结合此JSON样例,我们看下在 .Images.Image[].Status
作用下,最终返回值的获取过程。首先筛选出JSON中Key为Images
的结果,然后对结果继续筛选,获取Key为Image
的结果,该结果是一个数组,此时对所得结果进行迭代,迭代获取数组中的第一个元素,并将该元素中Key为 Status
的值作为与指定的条件比较的值,即检查'Available
'是否在['Available']
中。
API调用返回样例(JSON)
{
"PageNumber":1,
"TotalCount":24,
"PageSize":1,
"RequestId":"49CBCED4-C9B9-4851-BEB5-8FB5E5169E30",
"RegionId":"cn-hangzhou",
"Images":{
"Image":[
{
"ImageId":"suse11sp3_64_20G_aliaegis_20150428.vhd",
"OSType":"linux",
"Architecture":"x86_64",
"OSName":"SUSE Linux Enterprise Server 11 SP3 64位",
"DiskDeviceMappings":{
"DiskDeviceMapping":[
{
"Device":"/dev/xvda",
"Size":"20"
}
]
},
"ImageOwnerAlias":"system",
"Progress":"100%",
"Usage":"instance",
"CreationTime":"2015-05-06T09:01:32Z",
"Status":"Available",
"ImageVersion":"1",
"ImageName":"suse11sp3_64_20G_aliaegis_20150428.vhd",
"IsCopied":false,
"IsSubscribed":false,
"Platform":"SUSE",
"Size":20
}
]
}
}
jq语法手册
基础用法
通过Key筛选
jq表达式:".foo"
input:
{"foo": 42, "bar": "less interesting data"}
通过Index筛选
jq表达式:".[0]"
input:
[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
output:
{
"name": "JSON",
"good": true
}
通过Iterator筛选
jq表达式:".[]"
input:
["hello","world"]
output:
"hello"
"world"
jq表达式:".[]"
input:
[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
output:
{
"name": "JSON",
"good": true
}
{
"name": "XML",
"good": false
}
通过Pipe("|")筛选
jq表达式:".[]|.name"
input:
[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
output:
"JSON"
"XML"
构造Array
jq表达式:"[.user, .projects[]]"
input:
{"user":"stedolan", "projects": ["jq", "wikiflow"]}
output:
[
"stedolan",
"jq",
"wikiflow"
]
构造Mapping
jq表达式:"{user, title: .titles}"
input:
{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
output:
{
"user": "stedolan",
"title": [
"JQ Primer",
"More JQ"
]
}
jq表达式:"{(.user): .titles}"
input:
{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
output:
{
"stedolan": [
"JQ Primer",
"More JQ"
]
}
内建操作符和函数
Addition(+)
jq表达式:".a + 1"
input:
{"a": 7}
output:
8
jq表达式:".a + .b"
input:
{"a": [1,2], "b": [3,4]}
output:
[
1,
2,
3,
4
]
Subtraction(-)
jq表达式:". - ["xml", "yaml"]"
input:
["xml", "yaml", "json"]
output:
[
"json"
]
Length
jq表达式:"[.[]| length]"
input:
[[1,2], "string", {"a":2}, null]
output:
[
2,
6,
1,
0
]
Keys
jq表达式:"keys"
input:
{"abc": 1, "abcd": 2, "Foo": 3}
output:
[
"Foo",
"abc",
"abcd"
]
In
jq表达式:'.[] | in({"foo": 42})'
input:
["foo", "bar"]
output:
true
false
map
jq表达式:"map(.+1)"
input:
[1,2,3]
output:
[
2,
3,
4
]
map_values
jq表达式:"map_values(.+1)"
input:
{"a": 1, "b": 2, "c": 3}
output:
{
"a": 2,
"b": 3,
"c": 4
}
del
jq表达式:"del(.foo)"
input:
{"foo": 42, "bar": 9001, "baz": 42}
output:
{
"bar": 9001,
"baz": 42
}
select
jq表达式:'.[] | select(.id == "second")'
input:
[{"id": "first", "val": 1}, {"id": "second", "val": 2}]
output:
{
"id": "second",
"val": 2
}
jq表达式:"map(select(. >= 2))"
input:
[1,5,3,0,7]
output:
[
5,
3,
7
]
any
jq表达式:"any"
input:
[true, false]
output:
true
jq表达式:"any"
input:
[false, false]
output:
false
all
jq表达式:"all"
input:
[true, false]
output:
false
jq表达式:"all"
input:
[true, true]
output:
true
jq表达式:"all"
input:
[]
output:
true
jq表达式:"all"
input:
[]
output:
true
min、max
jq表达式:"min"
input:
[5,4,2,7]
output:
2
sort、sort_by
jq表达式:"sort"
input:
[8,3,null,6]
output:
[
null,
3,
6,
8
]
jq表达式:"sort_by(.foo)"
input:
[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]
output:
[
{
"foo": 2,
"bar": 1
},
{
"foo": 3,
"bar": 100
},
{
"foo": 4,
"bar": 10
}
]
index
jq表达式:'index(", ")'
input:
"a,b, cd, efg, hijk"
output:
3
split
jq表达式:'split(", ")'
input:
"a, b,c,d, e, "
output:
[
"a",
"b,c,d",
"e",
""
]
join
jq表达式:'join(", ")'
input:
["a","b,c,d","e"]
output:
"a, b,c,d, e"
jq表达式:'join(" ")'
input:
["a",1,2.3,true,null,false]
output:
"a 1 2.3 true false"
条件判断
if-then-else
jq表达式:
'if . == 0 then "zero"elif . == 1 then "one"else "many"end'
input:
2
output:
"many"
>, <,>=, <=,==,!=
jq表达式:
'.<5'
input:
2
output:
true
jq表达式: '.==5'
input:
2
output:
false
高级用法
变量
jq表达式:".bar as $x | .foo | . + $x"
input:
{"foo":10, "bar":200}
output:
210
jq表达式:". as $i|[(.*2|. as $i| $i), $i]"
input:
5
output:
[
10,
5
]
自定义函数
jq表达式:"def addvalue(f): . + [f]; map(addvalue(.[0]))"
input:
[[1,2],[10,20]]
output:
[
[
1,
2,
1
],
[
10,
20,
10
]
]
jq表达式:"def addvalue(f): f as $x | map(. + $x); addvalue(.[0])"
input:
[[1,2],[10,20]]
output:
[
[
1,
2,
1,
2
],
[
10,
20,
1,
2
]
]