运维编排场景系列-----如何使用jq
本文主要讲解在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中的使用 下面带大家分析下一些公共模版中jq表达式的使用。 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"} output: 42 通过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 ] ]