0

I'm about to lose my mind working with jq for the first time today. I've tried every ever so dirty way to make this work somehow. Let's get down to business:

I'm trying to further develop the pretty barebones API for Unifi Controllers for some use cases: https://dl.ui.com/unifi/6.0.41/unifi_sh_api

Here's some mock up data (the real json data is thousands of lines):

{
  "meta": {
    "rc": "ok"
  },
  "data": [
    {
      "_id": "61a0da77f730e404af0edc3c",
      "ip": "10.19.31.120",
      "mac": "ff:ec:ff:89:ff:58",
      "name": "Test-Accesspoint"
    }
  ]
}

Here is my advancedapi.sh

#!/bin/bash
source unifiapi.sh
unifi_login 1>dev/null

if [ "$1" ];
then
command=$1
shift
else
echo "Please enter command"
exit
fi
#jq -r '.data[] | "\(.name),\(.mac)"'

assembleKeys(){
c="0"
seperator=";"
keys=$(for i in "$@"
do
        c=$(expr $c + 1)
        if [ $c -gt 1 ];
        then
                echo -n "${seperator}\(.${i})"
        else
                echo -n "\(.${i})"
        fi
done
echo)
}

assembleJQ(){
c=0
jq=$(echo -en 'jq -r -j \x27.data[] | '
for i in "$@"
do
        if [ "$c" != "0" ];
        then
        echo -en ",\x22 \x22,"
        fi
c=1
echo -en ".$i"
done
echo -en ",\x22\\\n\x22\x27")
echo "$jq"
}


getDeviceKeys(){
assembleJQ "$@"



#unifi_list_devices | jq -r '.data[]' | jq -r "${keys}"
#export keys=mac
#export second=name
#unifi_list_devices | jq -r -j --arg KEYS "$keys" --arg SECOND "$second" '.data[] | .[$KEYS]," ",.[$SECOND],"\n"'

unifi_list_devices | $jq
#unifi_list_devices | jq -r -j '.data[] | .mac," ",.name,"\n"'
}

"$command" $@

Users should be able to call any function from the API with as many arguments as they want. So basically this:

#export keys=mac
#export second=name
#unifi_list_devices | jq -r -j --arg KEYS "$keys" --arg SECOND "$second" '.data[] | .[$KEYS]," ",.[$SECOND],"\n"'

which works, but only with a limited number of arguments. I want to pass $@ to jq.

I'm trying to get the name and mac-address of a device by calling:

./advancedapi.sh getDeviceKeys mac name

this should return the mac-address and name of the device. But it only gives me this:

jq -r -j '.data[] | .mac," ",.name,"\n"'
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
'.data[]
jq: 1 compile error

The top-most line being the jq command, which works perfectly fine when called manually.

The assembleKeys function was my attempt at generating a string that looks like this:

jq -r '.data[] | "\(.name),\(.mac)"'

Can anyone explain to me, preferably in-depth, how to do this? I'm going insane here!

Thanks!

2 Answers 2

2

I want to pass $@ to jq.

There are actually many ways to do this, but the simplest might be using the --args command-line option, as illustrated here:

File: check

#/bin/bash
echo "${@}"
jq -n '$ARGS.positional' --args "${@}" 

Example run:

./check 1 2 3
1 2 3
[
  "1",
  "2",
  "3"
]

Projection

Here's an example that might be closer to what you're looking for. Using your sample JSON:

File: check2

#/bin/bash
jq -r '
  def project($array):
    . as $in | reduce $array[] as $k ([]; . + [$in[$k]]);
  $ARGS.positional,
  (.data[] | project($ARGS.positional))
  | @csv
' input.json --args "${@}" 
./check2 name mac
"name","mac"
"Test-Accesspoint","ff:ec:ff:89:ff:58"

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, could you explain how I reference those within the jq stream? I want something like this: unifi_list_devices | jq -r -j --arg KEYS "$keys" --arg SECOND "$second" '.data[] | .[$KEYS]," ",.[$SECOND],"\n"' but with the arguments. All in all this needs to return a csv file.
Please see the added section.
I'm really grateful for you taking the time to help me with this, but even though the example you posted gives the output you specified this is so far away from my example and also far beyond my understanding of jq. Could you PLEASE post an example that applies to how to work with the mock-up data I posted? I'm absolutetly clueless as to what you did with the array. I understand you defined a function inside jq that shrinks the specified array of arguments down and then filters the array inside the statement to the values from the arguments, how do I get my array in there?
Updated, but you might find it worthwhile learning some jq basics.
Thanks a lot! I'm trying to, but what I'm trying to achieve is hardly "basics". Outputting pre-defined keys is easy, obviously, but I've never really had to work with json before other than a manual edit here and there.
0

enter image description here

There is error in the json (red highlighted commas)(that commas are not needed)


$
$ cat j.json | jq -r '.data[] | "\(.name)█\(.mac)█\(.ip)█\(._id)"'
Test-Accesspoint█ff:ec:ff:89:ff:58█10.19.31.120█61a0da77f730e404af0edc3c
$ cat j.json
{
  "meta": {
    "rc": "ok"
  },
  "data": [
    {
      "_id": "61a0da77f730e404af0edc3c",
      "ip": "10.19.31.120",
      "mac": "ff:ec:ff:89:ff:58",
      "name": "Test-Accesspoint"
    }
  ]
}
$

If the api have given this json you should probably edit it, before piping it into jq [maybe with sed or something like it]

1 Comment

Thanks but as stated the data was just mock-up data. My mistake here. Still this does not answer the question at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.