Bash: бесконечный сон (бесконечная блокировка)


Я использую startx запуск X, который будет оценивать мой .xinitrc. В моем .xinitrc Я запускаю свой оконный менеджер с помощью /usr/bin/mywm. Теперь, если я убью свой WM (для того, чтобы f.e. проверить некоторые другие WM), X тоже завершится, потому что .xinitrc сценарий будет достигнут конец файла. Поэтому я добавил Это в конце моего .xinitrc:

while true; do sleep 10000; done

таким образом, X не завершится, если я убью своего WM. Теперь мой вопрос: как я могу сделать бесконечного сна вместо циклического сна? Есть ли команда, которая будет нравится заморозить сценарий?

С наилучшими пожеланиями

9 99

9 ответов:

sleep infinity делает именно то, что он предлагает и работает без жестокого обращения с кошками.

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

tail не блок

как всегда: на все есть ответ, который является коротким, легко понять, легко следовать, и совершенно неправильно. Здесь tail -f /dev/null попадает в эту категорию ;)

если вы посмотрите на это с strace tail -f /dev/null вы заметите, что это решение далеко не блокирует! Это, наверное, даже хуже, чем sleep решение в вопросе, так как он использует (под Linux) драгоценные ресурсы, такие как ), мы сделали. К сожалению, это должно держать открытыми два PIDs и fifo.

вариант с именем fifo

если вы не утруждаете себя использованием имени fifo, вы можете сделать это следующим образом:

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

не используя цикл на чтение немного небрежно, но вы можете использовать это fifo так часто, как вам нравится, и сделать reads terminat с помощью touch "$HOME/.pause.fifo" (если есть более одного ожидания чтения, все они завершаются сразу).

или использовать Linux pause() syscall

для бесконечной блокировки есть вызов ядра Linux, называемый pause(), который делает то, что мы хотим: ждать вечно (пока не приходит сигнал). Однако для этого нет программы userspace (пока).

C

создать такую программу легко. Вот фрагмент для создания очень маленькой программы Linux под названием pause который останавливается на неопределенный срок (нуждается diet,gcc etc.):

printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause

python

если вы не хотите, чтобы скомпилировать что-то самостоятельно, но у вас есть python установлен, вы можете использовать это под Linux:

python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'

(Примечание: Используйте exec python -c ... чтобы заменить текущую оболочку, это освобождает один PID. Решение может быть улучшено с некоторым перенаправлением ввода-вывода, а также, освобождая неиспользуемые FDs. Это зависит от вас.)

как это работает (я думаю):ctypes.CDLL(None) загружает стандартную библиотеку C ++ и работает pause() функция в нем в пределах некоторого дополнительного цикла. Менее эффективен, чем версия C, но работает.

моя рекомендация для вас:

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

TL; DR:sleep infinity фактически спит максимальное допустимое время, которое является конечным.

интересно, почему это нигде не задокументировано, я потрудился прочитать источники из GNU coreutils и я обнаружил, что он выполняет примерно следующее:

  1. используйте strtod из C stdlib в первом аргументе для преобразования "бесконечности" в двойную точность. Итак, предполагая, что IEEE 754 двойная точность 64-бит положительная бесконечность значение хранится в seconds переменной.
  2. Invoke xnanosleep(seconds) ( найдено в gnulib), это в свою очередь вызывает dtotimespec(seconds) (также в gnulib) для преобразования из double до struct timespec.
  3. struct timespec это просто пара целых чисел: целая часть (в секундах) и дробная часть (в наносекундах). Наивно обращая положительная бесконечность to integer приведет к неопределенному поведению (см. §6.3.1.4 из стандарта C), поэтому вместо этого он усекается до TYPE_MAXIMUM (time_t).
  4. фактическое значение TYPE_MAXIMUM (time_t) не входит в стандарт (даже sizeof(time_t) нет); Итак, для примера давайте выберем x86-64 из недавнего ядра linux.

это TIME_T_MAX в ядре Linux, которое определено (time.h) как:

(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)

отметим, что time_t и __kernel_time_t и time_t и long; используется модель данных LP64, поэтому sizeof(long) 8 (64 бита).

что дает: TIME_T_MAX = 9223372036854775807.

это: sleep infinite приводит к фактическому времени сна 9223372036854775807 секунд (10^11 лет). И для 32-битных систем linux (sizeof(long) is 4 (32 бит): 2147483647 секунд (68 лет; см. Также проблему 2038 года).


Edit: видимо nanoseconds вызываемая функция не является непосредственно syscall, а зависящей от ОС оболочкой (также определено в gnulib).

в результате есть дополнительный шаг: для некоторых систем, где HAVE_BUG_BIG_NANOSLEEP и true время сна сокращается до 24 дней, а затем вызывается в цикле. Это касается некоторых (или всех?) Дистрибутивов Linux. Обратите внимание, что эта оболочка может не использоваться, если настроитьтест завершается успешно (источник).

в частности, это было бы 24 * 24 * 60 * 60 = 2073600 seconds (плюс 999999999 наносекунд), но это вызывается в цикле для того, чтобы соблюдать заданное общее время сна. Поэтому предыдущие выводы остаются в силе.


в заключение в результате время сна не бесконечно, но достаточно высоко для всех практических целей, даже если полученный фактический промежуток времени не переносится; это зависит от ОС и архитектуры.

чтобы ответить на исходный вопрос, это, очевидно, достаточно хорошо, но если по какой-то причине (a очень система с ограничением ресурсов) вы действительно хотите избежать бесполезного дополнительного таймера обратного отсчета, я думаю, что наиболее правильной альтернативой является использование cat метод, описанный в другой ответ.

sleep infinity выглядит наиболее элегантно, но иногда это не работает по какой-то причине. В этом случае вы можете попробовать другие команды блокировки, такие как cat,read,tail -f /dev/null,grep a etc.

Как насчет отправки SIGSTOP для себя?

это должно приостановить процесс до получения SIGCONT. Что в вашем случае: никогда.

kill -STOP "$$";
# grace time for signal delivery
sleep 60;

недавно у меня возникла необходимость сделать это. Я придумал следующую функцию, которая позволит Башу спать вечно без вызова какой-либо внешней программы:

snore()
{
    [[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:)
    read ${1:+-t ""} -u $_snore_fd || :
}

примечание: Я ранее опубликовал версию этого, которая будет открывать и закрывать файловый дескриптор каждый раз, но я обнаружил, что на некоторых системах, делающих это сотни раз в секунду, в конечном итоге заблокируется. Таким образом, новое решение сохраняет дескриптор файла между вызовами функции. Баш уберет его на выходе в любом случае.

Это можно назвать так же, как /bin/sleep, и он будет спать в течение запрошенного времени. Вызывается без параметров, он будет висеть вечно.

snore 0.1  # sleeps for 0.1 seconds
snore 10   # sleeps for 10 seconds
snore      # sleeps forever

здесь есть запись с чрезмерными деталями в моем блоге

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

while :; do read; done

нет ожидания процесса сна ребенка.