JQ: Select when attribute value exists in a bash array

。_饼干妹妹 提交于 2019-12-11 02:47:25

问题


I'm using jq 1.4. I trying to select elements when VPCZoneIdentifier exists in my $selected_subnets (bash variable).

selected_subnets="valueA valueB"

input='{"elements":[
           {"name": "nameA", "VPCZoneIdentifier": "valueA"}, 
           {"name": "nameB", "VPCZoneIdentifier": "valueB"}, 
           {"name": "nameC", "VPCZoneIdentifier": "valueC"}
       ]}'

test and match fn are only available on v1.5.


回答1:


This is a little tricky, but it can be done with reduce. The whole thing could look like this:

selected_subnets_json=$(echo "\"$selected_subnets\"" | jq -c -M 'split(" ")')
echo "$input" | jq -M '.elements = [.elements[] | select(.VPCZoneIdentifier as $id | '"$selected_subnets_json"' | reduce .[] as $v (false; . or $id == $v))]'

The first part makes a JSON array from the shell list:

$ echo "\"$selected_subnets\"" | jq -c -M 'split(" ")'
["valueA","valueB"]

The second part uses the reduce filter to compare the .VPCZoneIdentifier property with all elements of this array. With the selected_subnets_json variable expanded into it, the filter looks as follows:

.elements = [
  .elements[] |
    select(.VPCZoneIdentifier as $id |
           [ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))
]

That is to say, the elements property is overwritten with those elements of it that match the selection criterium

.VPCZoneIdentifier as $id | [ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))

Of this the first part remembers the VPCZoneIdentifier as $id (because . will shortly mean something entirely different), and

[ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))

is an or-reduction of the subnet array. It expands to false or $id == "valueA" or $id == "valueB" in this case.

If you prefer to have it all in one go, you could write

echo "$input" | jq -M '.elements = [.elements[] | select(.VPCZoneIdentifier as $id | ("'"$selected_subnets"'" | split(" ")) | reduce .[] as $v (false; . or $id == $v))]'

This works essentially the same way, except the splitting of $selected_subnets is done inline.




回答2:


You can set variables from the command line to be available in your queries using the --arg option. You can then filter out the elements using the select filter. Given an array of values, you could do a "value in array" test doing the following:

value == (array[])

So your filter would have the following structure:

.elements | map(
    select(
        .VPCZoneIdentifier == ($subnets | split(" ")[])
    )
)

Putting it all together with your variables:

$ echo $input | jq --arg subnets "$selected_subnets" '.elements | map(select(.VPCZoneIdentifier == ($subnets | split(" ")[])))'
[
  {
    "name": "nameA",
    "VPCZoneIdentifier": "valueA"
  },
  {
    "name": "nameB",
    "VPCZoneIdentifier": "valueB"
  }
]


来源:https://stackoverflow.com/questions/29142185/jq-select-when-attribute-value-exists-in-a-bash-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!