Home > Blockchain >  jq: how to select entries containing element in a mixed (scalar/list) value
jq: how to select entries containing element in a mixed (scalar/list) value

Time:08-03

I need to select values that have lists with a special element in some attributes:

Statement:
  - Effect: Allow
    Action:
      - s3:GetObject
      - s3:ListBucket
    Resource:
      - Fn::Join:
          - ''
          - - 'arn:aws:s3:::'
            - bucket*
      - Fn::Join:
          - ''
          - - 'arn:aws:s3:::'
            - bucket*
    
  - Effect: Allow
    Action: cloudformation:*
    Resource:
      - Fn::Join:
          - ''
          - - 'arn:aws:cloudformation:'
            - Ref: AWS::Region
            - ':'
            - Ref: AWS::AccountId
            - :stack/
            - Ref: AWS::StackName
            - /*

In this example, the first element must be selected, because its Action contains s3:GetObject.

If I try to use select here, it does not work, because in the second element, Action does not contain a list, and contains can't iterate over it.

$ cat action.yaml | yq -y '.Statement[].Action[]|contains("s3:GetObject")
jq: error (at <stdin>:1): Cannot iterate over string ("cloudforma...)

I can check if the element contains a list, using type:

$ cat action.yaml | yq -y '.Resources.InstanceRolePolicy.Properties.PolicyDocument.Statement[]|select(.Action|select(type=="array"))'

But how can I combine both checks in our select ?

CodePudding user response:

Put select(type=="array") after traversing to an element (here .Statement[].Action ) but before trying to iterate over its items ([]):

.Statement[].Action | select(type=="array")[] | contains("s3:GetObject")

Demo

Actually, there is a built-in shortcut to select(type=="array") called arrays, so this is equivalent:

.Statement[].Action | arrays[] | contains("s3:GetObject")

Demo

  • Related