Eu sei que posso esperar que uma condição se torne realidade no bash fazendo:
while true; do
test_condition && break
sleep 1
done
Mas ele cria 1 subprocesso a cada iteração (suspensão). Eu poderia evitá-los fazendo:
while true; do
test_condition && break
done
Mas ele usa muita CPU (espera ocupada). Para evitar subprocessos e espera ocupada, vim com a solução abaixo, mas acho feia:
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.
Nota: no caso geral, não posso simplesmente usar read -t 1 var
sem o fifo, porque ele consumirá o stdin e não funcionará se o stdin não for um terminal ou um pipe.
Posso evitar subprocessos e espera ocupada de uma maneira mais elegante?
bash
shell-script
sleep
jfg956
fonte
fonte
true
é um builtin e não cria um subprocesso no bash. A espera ocupada sempre será ruim.true
, pergunta atualizada.read -t 1 var
.sleep
o exemplo do primeiro exemplo. O segundo, embora funcione, não será fácil para ninguém se adaptar no futuro. O código simples também tem um potencial maior de segurança.Respostas:
Nas versões mais recentes
bash
(pelo menos v2), os componentes internos podem ser carregados (viaenable -f filename commandname
) no tempo de execução. Vários desses embutidos carregáveis também são distribuídos com as fontes do bash esleep
estão entre eles. A disponibilidade pode variar de sistema operacional para sistema operacional (e até de máquina para máquina), é claro. Por exemplo, no openSUSE, esses built-in são distribuídos através do pacotebash-loadables
.Editar: corrija o nome do pacote, adicione a versão mínima do bash.
fonte
sleep
como um builtin. Obrigado.Criar muitos subprocessos é uma coisa ruim em um loop interno. Criar um
sleep
processo por segundo é bom. Não há nada errado comSe você realmente deseja evitar o processo externo, não precisa manter o fifo aberto.
fonte
mkdir
que é feito pormktemp
(se não, é uma condição de corrida)). Também é verdade sobre owhile ! test_condition;
que é melhor do que a minha solução inicial.Recentemente, tive uma necessidade de fazer isso. Eu vim com a seguinte função que permitirá que o bash durma para sempre sem chamar nenhum programa externo:
NOTA: Eu publiquei anteriormente uma versão disso que abriria e fecharia o descritor de arquivos a cada vez, mas descobri que em alguns sistemas fazendo isso centenas de vezes por segundo acabaria travando. Portanto, a nova solução mantém o descritor de arquivo entre as chamadas para a função. Bash irá limpá-lo na saída de qualquer maneira.
Isso pode ser chamado como / bin / sleep e permanecerá no tempo solicitado. Chamado sem parâmetros, ele travará para sempre.
Há um artigo com detalhes excessivos no meu blog aqui
fonte
read -t 10 < <(:)
retorna imediatamente enquantoread -t 10 <> <(:)
aguarda os 10 segundos completos, mas ainda não entendi.read -t 10 <> <(:)
que<>
representa?Em
ksh93
oumksh
,sleep
é um shell embutido, portanto, uma alternativa pode ser usar essas conchas em vez debash
.zsh
também possui umzselect
built-in (carregado comzmodload zsh/zselect
) que pode dormir por um determinado número de centésimos de segundos comzselect -t <n>
.fonte
Como o usuário yoi disse, se no seu script for aberto o stdin , então, em vez do sleep 1, você pode simplesmente usar:
No Bash versão 4.1 e mais recente, você pode usar o número da bóia, por exemplo
read -t 0.3 ...
Se em um script o stdin estiver fechado (o script é chamado
my_script.sh < /dev/null &
), você precisará usar outro descritor aberto, que não produza saída quando a leitura é executada, por exemplo. stdout :Se em um script todo o descritor estiver fechado ( stdin , stdout , stderr ) (por exemplo, porque é chamado como daemon), será necessário encontrar qualquer arquivo existente que não produza saída:
fonte
read -t 1 3<&- 3<&0 <&3
é o mesmo queread -t 0
. É apenas a leitura de stdin com timeout.Isso funciona a partir de um shell de login e de um shell não interativo.
fonte
read -t 10 <> <(:)
.Você realmente precisa de um fifo? Redirecionar stdin para outro descritor de arquivo também deve funcionar.
Inspirado por: Leia a entrada no bash dentro de um loop while
fonte
Uma ligeira melhoria nas soluções mencionadas acima (nas quais baseei isso).
Reduziu a necessidade de um fifo e, portanto, nenhuma limpeza a ser feita.
fonte
read -t 10 <> <(:)
.