skip to Main Content

Consider the following json:

[
  {
    "val": 1,
    "name": "a"
  },
  {
    "val": 2,
    "name": "b"
  },
  {
    "val": 3,
    "name": "c"
  }
]

I want to pass an argument of space separated elements to jq and filter only these elements that have names matching to one of the argument elements. The following does not work, and I do not understand why – it only filters the first element. I suspect that $input is not updated. I do not know how to "join streams" to make it possible to use both streams at the same time – I have one stream the input and another is $names | split(" ").

$ jq -r --arg names 'a c' '.[] | select(. as $input | $names | split(" ") | index($input.name) == 0)' 1.json 
{
  "val": 1,
  "name": "a"
}

I have jq-1.5 available.

2

Answers


  1. You can make the comparison using IN (or any for jq < 1.6), for example:

    # jq 1.6
    jq --arg names 'a c' '.[] | select(IN(.name; ($names / " ")[]))'
    
    # jq 1.5
    jq --arg names 'a c' '.[] | select(any(.name == ($names / " ")[]; .))'
    

    If your search keys are unique, you could also build up an INDEX, and lookup the fields:

    # jq 1.6
    jq --arg names 'a c' 'INDEX(.name)[($names / " ")[]]'
    
    # jq 1.5
    jq --arg names 'a c' 'map({key:.name, value:.}) | from_entries[($names / " ")[]]'
    

    Output:

    {
      "a": 1,
      "name": "a"
    }
    {
      "c": 3,
      "name": "c"
    }
    
    Login or Signup to reply.
  2. Easiest is probably to split your names into an array first, then use IN to filter your stream:

    jq -r --arg names 'a c' '($names/" ") as $names
    | .[] | select(.name | IN($names[]))'
    

    Or using any:

    jq -r --arg names 'a c' '($names/" ") as $names
    | .[] | select(any(.name == $names[]; .))'
    

    (the latter simply inlines IN: def IN(s): any(s == .; .);)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search