4

I would like a string of all my HomePod ids. I can loop a file called players.json:

homepods=""
jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' players.json | while read homepod; do
    homepods+="$homepod,"
done

echo $homepods

I would expect the outcome to be id,id,id, but $homepods is empty. When I echo $homepods inside the loop the output is as expected.

2
  • can you add the sample input file? Commented Jun 28, 2018 at 12:47
  • players.json you mean? This is not the issue, the jq loop works. When I echo $homepod and/or $homepods the values are shown. Commented Jun 28, 2018 at 12:50

2 Answers 2

3

You can use the following script:-

homepods=""
for homepod in `jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' players.json` ; do
    homepods+="$homepod,";
done

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

Comments

2

The pipe starts a new process in a new environment which has a copy of the parent process' environment, hence it cannot change the parent variables.

So, you need an alternative approach:

homepods=$( 
    printf "%s," $(
    jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' players.json
))

In this case the parent is capturing the output of the child instead.

or alternatively:

homepods=$(
  jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' players.json | while read homepod; do
    echo "$homepod,"
  done)

Answering your additional request: you could also echo the counter and then split it up from the captured output. However, there is an easier alternative:

homepods_array=(${homepods//,/ })
homepods_count=${#homepods_array[@]}

That is converting the string to a bash array and then recovering the length of the array. That is also using bash string manipulation to replace the commas for spaces.

BTW, using string manipulation you can get your ids in many formats with no loops at all:

homepods_lines=$(jq -r '.data.players[]|select(.type == "airplay" and .is_multiple == false)|.id' players.json)
homepods_spaces=${homepods_lines//$'\n'/ }
homepods_commas=${homepods_lines//$'\n'/,}
homepods_array=(homepods_lines)
homepods_count=${#homepods_array[@]}

4 Comments

Great, that works. But what if I would like to create a second variable? I was hoping to create 2 variables while looping 1) homepods which holds the IDs and 2) a variable which is 5,5,5,etc ... based on the number of results from players.json
Would you mind adding an example? My Linux scripting skills don't yet match those of PHP :)
are those enough?
Thanks, I will also give this a try.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.