Понимание bash обработки сигналов - PullRequest
0 голосов
/ 29 марта 2020

Предисловие

Моим первоначальным намерением было написать скрипт, который каждую секунду проверяет, какое оборудование (может быть, раковина лучше?) Играет Spotify musi c (наушники , стерео, ...) так что эта информация надежна даже после завершения Spotify (например, это идентификатор аппаратного Spotify, который использовался, когда он был закрыт ).

Сценарий, который я изначально написал для этого, по сути был сценарием, который вызывает и анализирует pactl list в while true l oop для получения #id оборудования, на котором Spotify воспроизводит аудио.

Это работало, пока работал Spotify, но когда Spotify был закрыт, конечным результатом этого "слушателя" была пустая строка, что показалось бы мне нормальным, если бы pactl info был вызван после закрывая Spotify, но я подумал, что назвал это до .

На данный момент, я думаю, я мог неправильно понять, как обработка сигналов и trap s работают в bash .

М (не) МЫ * 10 26 * Чтобы дать себе и вам MWE, я придумал следующий сценарий: driver.sh, который запускает сценарий listener.sh в фоновом режиме и затем запускается Spotify не в фоновом режиме (насколько я понимаю, отправка сигнала в Spotify, например его закрытие, приводит к отправке этого сигнала на driver.sh); он также устанавливает trap, который завершает фоновый процесс. #!/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 скрипт, который бесконечно анализирует вывод pactl list для строки media.name в while true петля; trap гарантирует, что синтаксический анализ выполняется в последний раз после завершения. #!/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 Я думал, что при данной настройке извлечение driver.sh из терминала приведет к следующему. Spotify открывается, и терминал заполняется, секунда за секундой, строками вида func: media.name = "Spotify" func: media.name = "Spotify" func: media.name = "Spotify" ... При закрытии Spotify (убивая driver.sh или закрываясь Окно Spotify) еще две строки: trap: func: media.name = "Spotify" Вместо этого я получу, если закрою Spotify: ... func: media.name = "Spotify" func: media.name = "Spotify" +enrico:~$ trap: func: # empty! trap: func: # why again? Если вместо этого я CTRL + C driver.sh Я понял (мои комментарии): ... 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? Меня это озадачивает. Я думал, что после получения сигнала завершения, driver.sh должен захватить его с помощью trap и запустить команду kill -TERM $bg_pid, чтобы обработать его. В свою очередь, listener.sh после получения сигнала должен выполнить echo, затем func, затем exit. Только в этот момент Spotify должен прекратить работу. Если бы после звонка pactl list после этого не было бы Spotify, я бы понял. Очевидно, я, возможно, неправильно все понял.

1 Ответ

1 голос
/ 29 марта 2020

/usr/bin/spotify получает SIGINT и умирает до того, как driver.sh завершит listen.sh, таким образом, пустой вывод из pactl. Вы должны запустить /usr/bin/spotify в фоновом режиме и завершить его после завершения listen.sh.

Итак, ваши сценарии должны выглядеть так:

driver. sh

#!/bin/bash
trap 'kill -TERM $bg_pid $!' SIGINT SIGTERM
./listen.sh &
bg_pid=$!
echo "bg_pid: $bg_pid"
/usr/bin/spotify &
wait

прослушивание. sh

#!/bin/bash
trap 'echo trap:; func; exit' SIGINT SIGTERM
func() {
  echo func: $(pactl list | sed -E '/media\.name/p;d')
}
while true; do
  func
  sleep 1
done
...