Подтвердить что ты не робот

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

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

Я ищу способ построения бесконечного ожидания (не обязательно цикла) с помощью сценариев оболочки, чтобы он ожидал навсегда и может быть убит (или технически, чтобы получить 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. И при этом условии, что я ищу "идеальную" конструкцию бесконечного взгляда.

4b9b3361

Ответ 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