перехватить сигнал пользователя и продолжить выполнение - PullRequest
1 голос
/ 04 апреля 2020
#!/bin/sh
trap 'echo yo2 > $fifo' USR1

out(){ while read -r line; do echo $line; done; }

fifo=~/fifo
[ -e $fifo ] && rm $fifo
mkfifo fifo

tail -f > $fifo &
while :; do
    echo yo1 > $fifo
    sleep 1
done &

out < $fifo

Я пытаюсь перехватить сигнал USR1, чтобы отразить его в FIFO, который я оставил открытым в своем сценарии, но после получения сигнала FIFO закрывается и сценарий завершается.

Ответы [ 2 ]

1 голос
/ 04 апреля 2020

Краткий ответ

Когда оболочка обрабатывает сигнал с помощью trap, любой ожидающий в данный момент read завершится ошибкой. Вот почему сценарий завершается преждевременно.

Чтобы исправить это, установите флаг в обработчике. Затем, когда read не удается, проверьте флаг. Если флаг установлен, то вы знаете, что read не удалось из-за сигнала, а не конца файла, поэтому вам следует продолжить выполнение l oop.

Что происходит?

Во-первых, давайте немного упростим сценарий, а также добавим несколько распечаток, чтобы увидеть, что происходит. Вот trap-fifo1.sh:

#!/bin/sh

echo "my PID: $$"

trap handler USR1

handler() {
  echo "in 'handler'"
  echo caught_user1 > fifo
  echo "handler complete"
}

out() {
  echo "in 'out'"
  while read -r line; do
    echo $line
  done
  echo "loop terminated"
}

echo "about to invoke 'out'"
out < fifo
echo "at end of script"

Чтобы увидеть манифест проблемы, я собираюсь запустить три команды на трех разных терминалах. Каждый терминальный сеанс представлен столбцом, а вертикальная ось является глобальным временем:

Terminal 1              Terminal 2      Terminal 3
---------------         -------------   ----------------
$ ./trap-fifo1.sh
my PID: 42436
about to invoke 'out'
                        $ cat > fifo
in 'out'
                        hi
hi
                                        $ kill -s SIGUSR1 42436
in 'handler'
handler complete
loop terminated
at end of script

Значение l oop остановилось, когда мы отправили SIGUSR1. Это связано с тем, что ожидающий read сбой при получении и обработке сигнала. (Помимо: я изо всех сил пытался найти авторитетную ссылку на это эмпирически наблюдаемое поведение. Лучшее, что я нашел, это https://ss64.com/bash/trap.html, но я не знаю, откуда взялся этот текст. Я не смог найти его ни в одном из них POSIX ни bash руководство .)

Как мы можем это исправить?

Проблема заключается в неоднозначности в read, что мы не знаю, если это происходит из-за trap или из-за конца файла. Поэтому мы установим флаг в handler. Вот trap-fifo2.sh:

#!/bin/sh

echo "my PID: $$"

trap handler USR1

handler_invoked=false

handler() {
  echo "in 'handler'"
  echo caught_user1 > fifo
  handler_invoked=true
  echo "handler complete"
}

out() {
  echo "in 'out'"
  while true; do
    if read -r line; then
      echo $line
    elif $handler_invoked; then
      echo "flag set, continuing"
      handler_invoked=false
    else
      echo "flag unset, stopping"
      break
    fi
  done
  echo "after while loop"
}

echo "about to invoke 'out'"
out < fifo
echo "at end of script"

Теперь давайте посмотрим на исправление в действии:

Terminal 1              Terminal 2      Terminal 3
---------------         -------------   ----------------
$ ./trap-fifo2.sh
my PID: 42562
about to invoke 'out'
                        $ cat > fifo
in 'out'
                        hello
hello
                                        $ kill -s SIGUSR1 42562
in 'handler'
handler complete
flag set, continuing
caught_user1

                        again
again
                                        $ kill -s SIGUSR1 42562
in 'handler'
handler complete
flag set, continuing
caught_user1
                        (Ctrl+D)
flag unset, stopping
after while loop
at end of script

Оттуда нам нужно только адаптировать оригинальный скрипт, добавив флаг и отметив его в L oop, который должен быть простым.

0 голосов
/ 04 апреля 2020

Когда основной процесс получает SIGUSR1, он находится в середине чтения (внутренняя функция выходит). Мало что произойдет: * ожидание чтения приостановлено * ловушка активируется (добавление yo2 к fifo) * чтение возобновляется и немедленно завершается ошибкой с кодом ошибки * В то время как l oop in out завершается, и скрипт exit.

Возможно, вы захотите рассмотреть другое решение, в котором метод 'out' является фоновым, а сценарий 'main' будет обрабатывать только сигналы сигналов, ожидая, пока дочерний процесс завершится sh* 1003. *

Заменить линию, вне

out < $fifo &
# Loop forever. Add exit condition.
while true ; do wait ; done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...