Foreword
My initial intention was to write a script that keeps checking every 1 second what hardware (maybe sink is a better term?) is playing Spotify music (headphones, stereo,...) such that this information is reliable even after Spotify is terminated (as in, this is the id of the hardware Spotify was using when it got closed).
The script I initially wrote to do this, was essentially a script that calls and parses pactl list
in while true
loop to retrieve the #id of the hardware on which Spotify is playing audio.
This worked as long as Spotify was up, but when Spotify was closed, the final outcome of that "listener" was an empty string, which would seem ok to me if pactl info
was called after closing Spotify, but I thought I was calling it this before.
At this point, I think I might have misunderstood how signal handling and trap
s work in bash
.
The M(non)WE
In order to give to myself and to you a MWE, I came up with the following.
- A
driver.sh
script which launches alistener.sh
script in background and then starts Spotify not in background (my understanding is that doing so, sending a signal to Spotify, e.g. closing it, results in that signla being sent todriver.sh
); it also setstrap
which terminates the background process.
#!/bin/bash
trap 'kill -TERM $bg_pid' SIGINT SIGTERM EXIT
./listen.sh &
bg_pid=$!
echo "bg_pid: $bg_pid"
/usr/bin/spotify
- A
listener.sh
script which parsespactl list
's output for the linemedia.name
infinitely in awhile true
loop; thetrap
ensures that the parsing happens one last time upon termination.
#!/bin/bash
trap 'echo trap:; func; exit' SIGINT SIGTERM EXIT
func() {
echo func: $(pactl list | sed -E '/media\.name/p;d')
}
while true; do
func
sleep 1
done
I thought that, given this setting, exectuting driver.sh
from terminal would result in the following.
- Spotify opening up, and the terminal being filled, second by second with lines of the form
func: media.name = "Spotify"
func: media.name = "Spotify"
func: media.name = "Spotify"
...
- Upon closing Spotify (by killing
driver.sh
or closing Spotify window) two more line:
trap:
func: media.name = "Spotify"
Instead, what I get if I close Spotify is
...
func: media.name = "Spotify"
func: media.name = "Spotify"
+enrico:~$ trap:
func: # empty!
trap:
func: # why again?
If instead I CTRL+C driver.sh
I get this (comments are mine):
...
func: media.name = "Spotify"
func: media.name = "Spotify"
^Cfunc: media.name = "Spotify" # here I hit ctrl+c
func: media.name = "Spotify" # maybe this delay is because of sleep in listener.sh?
./spot.sh: line 6: 8704 Segmentation fault (core dumped) /usr/bin/spotify # why this SegV?
+enrico:~$ trap:
func: # empty!
trap:
func: # why again?
This is puzzling me. I thought that upon receiving the termination signal, driver.sh
should capture it with the trap
and run the kill -TERM $bg_pid
command to handle it. In turn, listener.sh
, upon receiving the signal, should execute echo
, then func
, then exit
. Only at this point should Spotify terminate. If calling pactl list
after this would have no Spotify in it, I would understand.
Apparently I have possibly misunderstood the whole thing.