Bash: бесконечный сон (бесконечная блокировка)
Я использую startx
для запуска X, который будет оценивать мой .xinitrc
. В моем .xinitrc
Я запускаю диспетчер окон с помощью /usr/bin/mywm
. Теперь, если я убью свой WM (для того, чтобы f.e. проверьте некоторые другие WM), X также завершится, потому что .xinitrc
скрипт достиг EOF.
Поэтому я добавил Это в конце моего .xinitrc
:
while true; do sleep 10000; done
таким образом, X не завершится, если я убью свой WM. Теперь мой вопрос: как я могу сделать бесконечного сна вместо циклического сна? Есть ли команда, которая будет нравится заморозить сценарий?
С наилучшими пожеланиями
9 ответов
может быть, это кажется уродливым, но почему бы просто не запустить cat
и пусть он ждет ввода навсегда?
tail
не блок
как всегда: для всего есть ответ, который короткий, легко понять, легко следовать и совершенно неправильно. Вот!--7--> попадает в эту категорию ;)
если вы посмотрите на это с strace tail -f /dev/null
вы заметите, что это решение далеко не блокирует! Это, вероятно, даже хуже, чем sleep
решение в вопросе, поскольку оно использует (под Linux) драгоценные ресурсы, такие как ), мы сделали. К сожалению, это должно держать открытыми два PIDs и A fifo
.
вариант с именем fifo
если вы не беспокоитесь об использовании именованного fifo
, вы можете сделать это следующим образом:
mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"
не использовать цикл на чтение немного небрежно, но вы можете использовать это fifo
так часто, как вам нравится, и сделать read
s 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 и я обнаружил, что он выполняет примерно следующее:
- используйте strtod из C stdlib в первом аргументе для преобразования "infinity" в двойную точность. Итак, предполагая, что IEEE 754 двойная точность 64-бит положительная бесконечность значение хранится в
seconds
переменной. - Invoke
xnanosleep(seconds)
(найти в в gnulib), это в свою очередь вызываетdtotimespec(seconds)
(также в gnulib) для преобразования изdouble
tostruct timespec
. -
struct timespec
- это всего лишь пара целых чисел: целая часть (в секундах) и дробная часть (в наносекундах). Наивно обращая положительная бесконечность to integer приведет к неопределенному поведению (см. §6.3.1.4 из стандарта C), поэтому вместо этого он усекаетTYPE_MAXIMUM (time_t)
. - фактическое значение
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
is __kernel_time_t
и time_t
is 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 года).
редактировать: видимо nanoseconds
вызываемая функция не является непосредственно syscall, а зависящей от ОС оболочкой (также определена в в gnulib).
в результате есть дополнительный шаг: для некоторых систем, где HAVE_BUG_BIG_NANOSLEEP
is 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;
недавно мне нужно было это сделать. Я придумал следующую функцию, которая позволит bash спать вечно без вызова какой-либо внешней программы:
snore()
{
[[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:)
read ${1:+-t ""} -u $_snore_fd || :
}
примечание: Я ранее опубликовал версию этого, которая будет открывать и закрывать файловый дескриптор каждый раз, но я обнаружил, что в некоторых системах, делающих это сотни раз в секунду, в конечном итоге закроется. Таким образом, новое решение сохраняет дескриптор файла между вызовами функции. Bash очистит его на выходе в любом случае.
Это можно назвать так же, как /bin/sleep, и он будет спать в течение запрошенного времени. Вызванный без параметров, он будет висеть вечно.
snore 0.1 # sleeps for 0.1 seconds
snore 10 # sleeps for 10 seconds
snore # sleeps forever
вместо того, чтобы убивать оконный менеджер, попробуйте запустить новый с --replace
или -replace
если таковые имеются.