Я знаю, что могу подождать, пока условие станет истинным в bash, выполнив:
while true; do
test_condition && break
sleep 1
done
Но он создает 1 подпроцесс на каждую итерацию (сон). Я мог бы избежать их, сделав:
while true; do
test_condition && break
done
Но он использует много процессора (занят ожидания). Чтобы избежать подпроцессов и напряженного ожидания, я придумал решение, приведенное ниже, но нахожу его уродливым:
my_tmp_dir=$(mktemp -d --tmpdir=/tmp) # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo # Open the fifo for reading and writing.
while true; do
test_condition && break
read -t 1 -u 3 var # Same as sleep 1, but without sub-process.
done
exec 3<&- # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir # Cleanup, could be done in a trap.
Примечание: в общем случае я не могу просто использовать read -t 1 var
без fifo, потому что он будет использовать stdin и не будет работать, если stdin не является терминалом или каналом.
Могу ли я избежать подпроцессов и занятого ожидания более элегантным способом?
bash
shell-script
sleep
jfg956
источник
источник
true
является встроенным и не создает подпроцесс в Bash. Ожидание всегда будет плохо.true
, вопрос обновлен.read -t 1 var
.sleep
принципу, что и в первом примере. Второй способ, хотя он и может работать, не будет легко адаптироваться в будущем. Простой код также имеет больший потенциал для безопасности.Ответы:
В более новых версиях
bash
(по крайней мере v2) встроенные функции могут быть загружены (черезenable -f filename commandname
) во время выполнения. Ряд таких загружаемых встроенных программ также распространяется вместе с исходными кодами bash иsleep
входит в их число. Конечно, доступность зависит от ОС к ОС (и даже от машины к машине). Например, в openSUSE эти встроенные функции распространяются через пакетbash-loadables
.Редактировать: исправить имя пакета, добавить минимальную версию bash.
источник
sleep
как встроенный. Благодарю.Создание большого количества подпроцессов - плохая вещь во внутреннем цикле. Создание одного
sleep
процесса в секунду - это нормально. Там нет ничего плохого вЕсли вы действительно хотите избежать внешнего процесса, вам не нужно держать fifo открытым.
источник
mkdir
как это делаетсяmktemp
(если нет, это условие гонки)). Также верно в отношении того,while ! test_condition;
что лучше, чем мое первоначальное решение.У меня недавно была необходимость сделать это. Я придумал следующую функцию, которая позволит bash спать вечно без вызова какой-либо внешней программы:
ПРИМЕЧАНИЕ. Ранее я публиковал эту версию, в которой каждый раз открывался и закрывался дескриптор файла, но обнаружил, что в некоторых системах, выполняющих эту операцию сотни раз в секунду, в конечном итоге происходит блокировка. Таким образом, новое решение сохраняет дескриптор файла между вызовами функции. Bash все равно очистит его при выходе.
Это можно вызвать так же, как / bin / sleep, и он будет спать в течение запрошенного времени. Вызывается без параметров, он будет висеть вечно.
В моем блоге есть рецензия с чрезмерными подробностями
источник
read -t 10 < <(:)
возвращается сразу, покаread -t 10 <> <(:)
ждет полных 10 секунд, но я все еще не понимаю.read -t 10 <> <(:)
чем же<>
стоять?В
ksh93
илиmksh
,sleep
это встроенная команда оболочки, поэтому альтернативой может быть использование этих оболочек вместоbash
.zsh
также имеетzselect
встроенный (загруженныйzmodload zsh/zselect
), который может спать в течение определенного количества сотых секунд сzselect -t <n>
.источник
Как сказал пользователь yoi , если в вашем скрипте открыт stdin , то вместо sleep 1 вы можете просто использовать:
В Bash версии 4.1 и новее вы можете использовать число с плавающей точкой, например
read -t 0.3 ...
Если в скрипте stdin закрыт (скрипт вызывается
my_script.sh < /dev/null &
), то вам нужно использовать другой открытый дескриптор, который не выдает вывод при выполнении чтения , например. стандартный вывод :Если в скрипте весь дескриптор закрыт ( stdin , stdout , stderr ) (например, потому что он называется daemon), то вам нужно найти любой существующий файл, который не производит вывод:
источник
read -t 1 3<&- 3<&0 <&3
так же, какread -t 0
. Это просто чтение из stdin с таймаутом.Это работает из оболочки входа в систему, а также из неинтерактивной оболочки.
источник
read -t 10 <> <(:)
.Тебе действительно нужна пятерка? Перенаправление stdin на другой дескриптор файла также должно работать.
Вдохновлено: чтение ввода в bash внутри цикла while
источник
Небольшое улучшение вышеупомянутых решений (на которых я это основал).
Уменьшена потребность в fifo и, следовательно, нет необходимости делать уборку.
источник
read -t 10 <> <(:)
.