skip to Main Content

I need to run a script where I have an array of ids, and a json that contains elements with these ids and more data. I need to filter/select the values that matches the ones in the array. For some reason, when running directly on bash I got good results with some of the things I’ve tried, but not when running with a script. Not sure if this may be relevant or I did something wrong when passing from one to the other

For example, if I have a json file like

[
 {
   "id": 1,
   "value": 10
 },   
 {
   "id": 2,
   "value": 100
 },
 {
   "id": 3,
   "value": 5
 },
 {
   "id": 4,
   "value": 17
 },
 {
   "id": 5,
   "value": 84
 }
]

And the following array:

IDS=(1 2 3 4)

I need to retrieve the values 10, 100, 5 and 17.

I’ve tried some ways:

VALUES=$(jq --argjson IDS "$IDS" '.[] | select( $IDS =~ .id ) | .value' file.json)
VALUES=$(jq --argjson IDS "$IDS" '.[] | select( ${IDS[*]} =~ .id ) | .value' file.json)
# I have certainty that IDS will always have 4 elements, no more no less
VALUES=$(jq --argjson IDS "$IDS" '.[] | select( .id == ${IDS[0]} | .id == ${IDS[1]} | .id == ${IDS[2]} | .id == ${IDS[3]} ) | .value' file.json)

In all cases I’m getting `unexpected INVALID_CHARACTER (Unix shell quoting issues?)

Also, on the last case, when I replaced the ${IDS[n]} for a hardcoded number, it worked fine. Yet, I won’t have the same numbers on each run, so I need that parametrized.

Any help would be great!

EDIT

Thanks everyone for the solutions. I kept the one I understood the most for now, but I’m really greatful with all

4

Answers


  1. You’re looking for something like this:

    $ IDS=(1 2 3 4)
    $ jq '.[] | select(IN(.id; $ARGS.positional[])) .value' file.json --jsonargs "${IDS[@]}"
    10
    100
    5
    17
    
    Login or Signup to reply.
  2. Use --arg and then convert the Bash array to JSON integers:

    ($IDS | split(" ") | map(tonumber)) as $PIDS
    

    Combine that with select() and index():

    jq 
        --arg IDS "${IDS[*]}" 
        '($IDS | split(" ") | map(tonumber)) as $PIDS | 
            .[] | select([.id] | index($PIDS[])).value' 
    input
    

    Gives:

    10
    100
    5
    17
    
    Login or Signup to reply.
  3. One approach is to create a map of acceptable IDs and then do lookups within it:

    ids=( 1 2 3 4 )
    
    jq --arg idstr "${ids[*]}" '
      ([$idstr | split(" ")[] | {"key": ., "value": true}] | from_entries) as $idmap
      | .[] | select($idmap[.id | tostring]).value'
    
    Login or Signup to reply.
  4. Alternatively, pass ids individual array elements as arguments to jq using --args "${ids[@]}" and read the values back into a bash array with mapfile:

    #!/usr/bin/env bash
    
    ids=( 1 2 3 4 )
    
    mapfile -t values < <(
    
    jq '
      (
        [$ARGS.positional[] | {"key": ., "value": true}] |
        from_entries
      ) as $idmap |
      .[] |
      select($idmap[.id | tostring]).value' 
      input.json 
      --args "${ids[@]}" 
    )
    
    # Debug show content of values array
    declare -p values
    

    Sample output:

    declare -a values=([0]="10" [1]="100" [2]="5" [3]="17")
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search