Внедрение бесконечного ожидания в сценариях оболочки
Это может показаться тривиальным, но я уверен, что этот вопрос не задан, или, по крайней мере, я не могу его найти.
Я ищу способ построения бесконечного ожидания (не обязательно цикла) с помощью сценариев оболочки, чтобы он ожидал навсегда и может быть убит (или технически, чтобы получить SIGTERM
). Ниже приведены возможные конструктивные и аргументированные аргументы:
-
while true; do sleep 1; done
Это почти получается, но поскольку sleep
- внешняя команда, когда я отправляю SIGTERM
на запущенный script, он должен дождаться завершения sleep
, а затем обработать сигнал. Измените sleep 1
на что-то вроде sleep 10
, и отставание будет очевидно. Также решение пробуждает процессор каждые 1 секунду, что не идеально.
-
while true; do read; done
Это идеально, когда stdin
есть tty. read
- это встроенная оболочка, а SIGTERM
мгновенно появляется в script. Но, когда stdin
является /dev/null
, script использует весь процессор, беспомощно запуская read
навсегда на /dev/null
.
Таким образом, требуется встроенная конструкция оболочки, которая ждет вас навсегда. Прокрутка через man dash
Я не нашел такого - единственные блокирующие встроенные элементы read
и wait
, и у меня нет идеи, как я могу построить идеальный с помощью wait
.
Ответ должен быть применим к оболочке POSIX (эффективно dash
) или менее предпочтительно Bash.
Дополнительные примечания.
Ситуация, когда первый пример не работает отлично, сложнее, чем я думал. Со следующей оболочкой script:
#!/bin/sh
echo $$
while true; do
sleep 100
done
если вы убьете его на другом tty, он немедленно прекратится. Самое смешное начинается, когда вы пытаетесь поймать ловушку. С помощью этого script:
#!/bin/sh
at_term() {
echo 'Terminated.'
exit 0
}
trap at_term TERM
echo $$
while true; do
sleep 20
done
То, что происходит, точно описано в примере 1. Это происходит с bash, тире и zsh. И при этом условии, что я ищу "идеальную" конструкцию бесконечного взгляда.
Ответы
Ответ 1
вы можете использовать именованный канал для чтения:
mkfifo /tmp/mypipe
#or mknode /tmp/mypipe p
если позже вы захотите отправить в трубку различные произвольные "сигналы", чтение может использоваться в сочетании с аргументом case для принятия соответствующих действий (даже полезных)
while read SIGNAL; do
case "$SIGNAL" in
*EXIT*)break;;
*)echo "signal $SIGNAL is unsupported" >/dev/stderr;;
esac
done < /tmp/mypipe
Ответ 2
Если у вас есть GNU coreutils, который принимает секунды с плавающей запятой, вы можете попробовать:
sleep inf
Это должно блокироваться до тех пор, пока не будет потеряна временная метка 64-битного кода.
Ответ 3
Здесь решение без цикла:
#!/usr/local/bin/dash
echo $$
# -$$: kill process group (parent and children)
#trap 'trap - TERM; kill 0' TERM
#trap 'trap - INT TERM; kill 0' INT TERM
trap 'trap - TERM; kill -s TERM -- -$$' TERM
tail -f /dev/null & wait
exit 0
Ответ 4
Что не так с вашим вторым вариантом, но заставляя его читать с stdin
? (Требуется bash
)
while true; do
read
done < /dev/stdin
От man bash
Bash обрабатывает несколько имен файлов, особенно когда они используются в перенаправления, как описано в следующей таблице:
/dev/stdin
File descriptor 0 is duplicated.
Ответ 5
#!/bin/sh
at_term() {
echo 'Terminated.'
exit 0
}
trap at_term TERM
echo $$
while true; do
sleep 20 &
wait $!
done
Ответ 6
SIGTERM, отправленный процессу, доставляется ядром в процесс, независимо от того, спал он или нет.
Попробуйте поэкспериментировать, возможно, так (пример bash)
sleep 20 &
kill $! && fg