0

I have a json file that looks like this:

{"data":{"players":[{"id":"aaaa","is_multiple":false,"name":"TV Woonkamer","password_protected":false,"support_seek":false,"support_set_volume":false,"type":"upnp"},{"id":"bbbb","is_multiple":false,"name":"squeezelite","password_protected":false,"support_seek":true,"support_set_volume":true,"type":"upnp"},{"id":"cccc","is_multiple":false,"name":"Woonkamer","password_protected":false,"support_seek":true,"support_set_volume":true,"type":"airplay"},{"id":"__dddd__","is_multiple":true,"name":"Multiple AirPlay Devices","password_protected":false,"support_seek":true,"support_set_volume":true,"type":"airplay"}]},"success":true}

Parsed by PHP:

stdClass Object
(
[data] => stdClass Object
    (
        [players] => Array
            (
                [0] => stdClass Object
                    (
                        [id] => uuid:aaaa
                        [is_multiple] => 
                        [name] => TV Woonkamer
                        [password_protected] => 
                        [support_seek] => 
                        [support_set_volume] => 
                        [type] => upnp
                    )

                [1] => stdClass Object
                    (
                        [id] => uuid:bbbb
                        [is_multiple] => 
                        [name] => squeezelite
                        [password_protected] => 
                        [support_seek] => 1
                        [support_set_volume] => 1
                        [type] => upnp
                    )

                [2] => stdClass Object
                    (
                        [id] => cccc
                        [is_multiple] => 
                        [name] => Woonkamer
                        [password_protected] => 
                        [support_seek] => 1
                        [support_set_volume] => 1
                        [type] => airplay
                    )

                [3] => stdClass Object
                    (
                        [id] => __dddd__
                        [is_multiple] => 1
                        [name] => Multiple AirPlay Devices
                        [password_protected] => 
                        [support_seek] => 1
                        [support_set_volume] => 1
                        [type] => airplay
                    )

            )

    )

[success] => 1
)

I would like to loop through it from a linux command line and found all IDs of players where is_multiple is empty and type is airplay. The following shows a list of all players with type is airplay, but how do I start a loop?

jq '.data .players[]' scan.json | jq 'select(.type=="airplay")' | jq -r '.id'
vespino
  • 1,714
  • 3
  • 15
  • 28
  • 2
    That is not JSON at all! It looks like PHP's variable dump (If I recall correctly). – UltraInstinct Jun 18 '18 at 06:10
  • My bad, you're correct this is what it looks liked when parsing it with PHP. – vespino Jun 18 '18 at 06:36
  • I guess you want to call a command for each of the ids..? Try eg `| xargs -I{} command {}`. (btw the jq commands can be piped inside the jq language - like `< scan.json jq -r '.data .players[]|select(.type=="airplay")|.id'`. – liborm Jun 18 '18 at 08:43
  • @liborm help, I'm quit new to this. Do you have a complete example for me? – vespino Jun 18 '18 at 08:50
  • You need to be more specific about what your 'loop' is supposed to do. – liborm Jun 18 '18 at 08:52
  • @liborm I would like to be able to perform a command using the id of every player where is_multiple is empty and type is airplay. So I need a variable with the value of id for each player basically. – vespino Jun 18 '18 at 08:54

2 Answers2

1

I believe the code you're after is something like

<scan.json jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' |
   xargs -I{} wget -q "https://my.web/?id={}"

If the operation with each id is more complex, you can wrap it either in a .sh script, or in a bash function (like process_one_id(){ commands.. ;}.

NB: to use a bash function with xargs you have to do export -f process_one_id and then call it through bash like xargs -I {} bash -c process_one_id {}. Or use GNU parallel which makes it transparent to call exported shell functions.

liborm
  • 2,634
  • 20
  • 32
  • Thanks, that indeed shows the list I'm looking for, but would you mind explaining me how to use it so I can use the output (ID) as a variable? E.g. calling a wget using the ID? – vespino Jun 18 '18 at 09:25
  • The `{}` string is your 'variable' in the `xargs` call. Updated the answer accordingly. – liborm Jun 18 '18 at 11:14
  • Seeing adding the commands inline will create a very long command (I'm running several commands for each ID), I was hoping on using a function so I created a simple "function test() { }", but I can't seem to find out how to call that function. Simply adding test after -I{} results in xargs: test: No such file or directory – vespino Jun 18 '18 at 11:41
  • Ah, sorry, my bad. Calling a bash function from `xargs` is a little more complicated. You can either use the trick mentioned [here](https://stackoverflow.com/a/11003457/1496234) or use `GNU parallel` instead of `xargs`, which will make the if more transparent. – liborm Jun 18 '18 at 11:57
0

I solved it as followed:

jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' players.json | while read i; do
    # i is the id of the player
    echo $i
done

Thanks @liborm for helping me on my way!

vespino
  • 1,714
  • 3
  • 15
  • 28