Ответ 1
sleep infinity
делает именно то, что он предлагает, и работает без кошачьих злоупотреблений.
Я использую startx
для запуска X, который будет оценивать мой .xinitrc
. В моем .xinitrc
я запускаю свой оконный менеджер, используя /usr/bin/mywm
. Теперь, если я убью свой WM (для проверки другого WM), X также закончится, потому что .xinitrc
script достигнут EOF.
Поэтому я добавил это в конце моего .xinitrc
:
while true; do sleep 10000; done
Таким образом, X не закончится, если я убью свой WM. Теперь мой вопрос: как я могу сделать бесконечный сон вместо того, чтобы зацикливаться? Есть ли команда, которая будет похожа на замораживание script?
С наилучшими пожеланиями
sleep infinity
делает именно то, что он предлагает, и работает без кошачьих злоупотреблений.
Возможно, это кажется уродливым, но почему бы просто не запустить cat
и не дождаться ввода навсегда?
tail
не блокирует Как всегда: для всего есть ответ, который короток, прост для понимания, легок для понимания и совершенно неверен. Здесь tail -f/dev/null
попадает в эту категорию;)
Если вы посмотрите на это с помощью strace tail -f/dev/null
вы заметите, что это решение далеко не блокирует! Это, вероятно, даже хуже, чем sleep
решение в вопросе, поскольку оно использует (под Linux) драгоценные ресурсы, такие как система inotify
. Также другие процессы, которые пишут в /dev/null
делают tail
петлю. (На моем Ubuntu64 16.10 это добавляет несколько 10 системных вызовов в секунду в уже загруженной системе.)
Читайте: я не знаю, как архивировать это с помощью оболочки напрямую.
Все (даже sleep infinity
) может быть прервано каким-либо сигналом. Поэтому, если вы хотите быть действительно уверенным, что он не исключительно возвращается, он должен работать в цикле, как вы уже делали для sleep
. Обратите внимание, что (в Linux) /bin/sleep
видимому, ограничен 24 днями (посмотрите на strace sleep infinity
), поэтому, вероятно, лучшее, что вы можете сделать, это:
while :; do sleep 2073600; done
(Обратите внимание, что я полагаю, что sleep
цикл внутренне для более высоких значений, чем 24 дня, но это означает: он не блокирует, он очень медленно зацикливается. Так почему бы не переместить этот цикл наружу?)
fifo
Вы можете создать что-то, что действительно блокирует, пока нет никаких сигналов, посылаемых процессу. Следующее использует bash 4
, 2 PID и 1 fifo
:
bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'
Вы можете проверить, что это действительно блокирует с помощью strace
если вам нравится:
strace -ff bash -c '..see above..'
read
блоки, если нет входных данных (см. некоторые другие ответы). Тем не менее, tty
(он же stdin
) обычно не является хорошим источником, так как он закрывается, когда пользователь выходит из системы. Также это может украсть некоторый вклад от tty
. Не хорошо.
Чтобы сделать блок read
, нам нужно подождать что-то вроде fifo
которое никогда ничего не вернет. В bash 4
есть команда, которая может предоставить нам такой fifo
: coproc
. Если мы также подождем, пока не будет выполнено блокирующее read
(что является нашей coproc
), мы закончили. К сожалению, для этого нужно держать открытыми два PID и fifo
.
fifo
Если вы не удосужились использовать именованный fifo
, вы можете сделать это следующим образом:
mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"
Не использовать цикл для чтения - это немного неаккуратно, но вы можете использовать эту fifo
столько раз, сколько захотите, и завершить read
используя touch "$HOME/.pause.fifo"
(если touch "$HOME/.pause.fifo"
более одного чтения, все прекращаются сразу).
pause()
Для бесконечной блокировки существует вызов ядра Linux, называемый pause()
, который делает то, что мы хотим: ждать вечно (пока не поступит сигнал). Однако для этого пока нет программы для пользователя.
Создать такую программу легко. Вот фрагмент кода для создания очень маленькой программы для Linux, называемой pause
которая делает паузу на неопределенный срок (нужна diet
, gcc
и т.д.):
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. Решение может быть улучшено также путем некоторого перенаправления ввода-вывода, освобождая неиспользуемые FD. Это ваше дело.)
Как это работает (я думаю): ctypes.CDLL(None)
загружает стандартную библиотеку C и запускает в ней функцию pause()
в некотором дополнительном цикле. Менее эффективен, чем версия C, но работает.
Оставайтесь в зацикленном сне. Это легко понять, очень переносимо и блокирует большую часть времени.
TL; DR: sleep infinity
самом деле спит максимально допустимое время, которое является конечным.
Удивляясь, почему это нигде не задокументировано, я потрудился прочитать исходники из GNU coreutils и обнаружил, что он выполняет примерно следующее:
strtod
из C stdlib для первого аргумента, чтобы преобразовать бесконечность в двойную точность. Таким образом, при условии двойной точности IEEE 754 64-битное положительное значение бесконечности сохраняется в переменной seconds
.xnanosleep(seconds)
(находится в gnulib), это, в свою очередь, вызывает dtotimespec(seconds)
(также в gnulib) для преобразования из double
в struct timespec
.struct timespec
- это просто пара чисел: целая часть (в секундах) и дробная часть (в наносекундах). Наивное преобразование положительной бесконечности в целое число приведет к неопределенному поведению (см. §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
равно __kernel_time_t
а time_t
long
; используется модель данных LP64, поэтому sizeof(long)
равен 8 (64 бита).
Что приводит к: TIME_T_MAX = 9223372036854775807
.
То есть: sleep infinite
приводит к фактическому времени сна 9223372036854775807 секунд (10 ^ 11 лет). А для 32-битных систем Linux (sizeof(long)
равен 4 (32 бита)): 2147483647 секунд (68 лет; см. Также проблему 2038 года).
Редактировать: очевидно, nanoseconds
функция nanoseconds
- это не системный вызов, а зависимая от ОС оболочка (также определенная в gnulib).
В результате возникает дополнительный шаг: для некоторых систем, где HAVE_BUG_BIG_NANOSLEEP
имеет значение true
сон усекается до 24 дней, а затем вызывается в цикле. Это касается некоторых (или всех?) Дистрибутивов Linux. Обратите внимание, что эта оболочка может не использоваться, если тест во время настройки завершился успешно (источник).
В частности, это будет 24 * 24 * 60 * 60 = 2073600 seconds
(плюс 999999999 наносекунд); но это вызывается в цикле для соблюдения указанного общего времени ожидания. Поэтому предыдущие выводы остаются в силе.
В заключение, результирующее время сна не бесконечно, но достаточно велико для всех практических целей, даже если результирующий фактический промежуток времени не является переносимым; это зависит от ОС и архитектуры.
Чтобы ответить на первоначальный вопрос, это, очевидно, достаточно хорошо, но если по какой-то причине (система с очень ограниченными ресурсами) вы действительно хотите избежать бесполезного дополнительного таймера обратного отсчета, я думаю, что наиболее правильной альтернативой является использование метода cat
описанного в другом ответы.
sleep infinity
выглядит очень элегантно, но иногда он не работает по какой-то причине. В этом случае вы можете попробовать другие команды блокировки, такие как cat
, read
, tail -f /dev/null
, grep a
и т.д.
Как насчет отправки SIGSTOP себе?
Это должно приостановить процесс до получения SIGCONT. Что в вашем случае: никогда.
kill -STOP "$$";
# grace time for signal delivery
sleep 60;
У меня недавно была необходимость сделать это. Я придумал следующую функцию, которая позволит bash бездействовать без вызова какой-либо внешней программы:
snore()
{
local IFS
[[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null ||
{
# workaround for MacOS and similar systems
local fifo
fifo=$(mktemp -u)
mkfifo -m 700 "$fifo"
exec {_snore_fd}<>"$fifo"
rm "$fifo"
}
read ${1:+-t "$1"} -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
, если он доступен.
Этот подход не потребляет ресурсов для поддержки процесса.
while :; do sleep 1; done & kill -STOP $! && wait $!
while :; do sleep 1; done &
while :; do sleep 1; done &
Создает фиктивный процесс в фоновом режимеkill -STOP $!
Останавливает фоновый процессwait $!
Подождите, пока фоновый процесс, это будет блокировать навсегда, потому что фоновый процесс был остановлен доwhile :; do read; done
не ждет процесса спящего ребенка.