Реализация бесконечного ожидания в сценариях shell

Это может показаться тривиальным, но я уверен, что этот вопрос еще не задавался, или, по крайней мере, я не могу его найти.

Я ищу способ построить бесконечное ожидание (не обязательно цикл) с помощью сценариев shell так, чтобы оно ждало вечно и могло быть убито (или, технически, получить SIGTERM). Ниже приведены известные возможные конструкции и аргументы против них:

  1. while true; do sleep 1; done Это почти получается, но поскольку sleep является внешней командой, когда я посылаю SIGTERM запущенному скрипту, он должен сначала дождаться завершения sleep, а затем обработать сигнал. Измените sleep 1 на что-то вроде sleep 10 и отставание станет очевидным. Также это решение будит процессор каждые 1 секунду, что не идеально.
  2. while true; do read; done Это идеально, когда stdin является tty. read является встроенной функцией оболочки и SIGTERM поступает в скрипт мгновенно. Но когда stdin - это /dev/null, сценарий съедает весь процессор, беспомощно выполняя read вечно на /dev/null.

Таким образом, требуется встроенная конструкция оболочки, которая ждет вечно. Пролистав man dash, я не нашел такой конструкции - единственные блокирующие встроенные модули это read и wait, и я не представляю, как я могу построить идеальный вариант, используя wait.

Ответ должен быть применим к POSIX shell (эффективно dash), или, что менее предпочтительно, к Bash.

Дополнительные замечания.

Ситуация, когда первый пример не работает идеально, сложнее, чем я думал. Со следующим shell-скриптом:

#!/bin/sh
echo $$
while true; do
    sleep 100
done

если убить его на другом tty, он немедленно завершается. Самое интересное начинается, когда вы пытаетесь сделать треппинг. С этим скриптом:

#!/bin/sh
at_term() {
    echo 'Terminated.'
    exit 0
}
trap at_term TERM
echo $$
while true; do
    sleep 20
done

Происходит то, что описано в примере 1. Это происходит с bash, dash и zsh. И именно при этом условии я ищу "идеальную" конструкцию бесконечного вида.

22
задан xiaq 30 January 2015 в 21:11
поделиться