Shell: é possível atrasar um comando sem usar `sleep '?
21
Existem substitutos, alternativas ou truques do bash para atrasar comandos sem usar sleep? Por exemplo, executando o comando abaixo sem realmente usar o modo de suspensão:
Não há outro motivo real além da curiosidade. Eu pensei que seria interessante aprender algumas soluções alternativas. Eu acho que atpode ser um, mas não consegui encontrar nenhum exemplo de uso.
user321697
1
@ user321697 “at” é agendar trabalhos únicos. eles são executados pelo serviço atd, para não pausar seu script de shell. um caso de uso para at seria fazê-lo em um horário especificado (assíncrono) e criar um arquivo de marcador quando terminar, enquanto o script aguarda que esse arquivo apareça em um loop while. você pode obter um efeito semelhante agendando um trabalho para enviar seu script a um SIGCONT e congelando-o, enviando a si mesmo um SIGSTOP.
Grega Bremec
1
Eu vim aqui esperando que todos sugerissem um spinlock. Estou agradavelmente surpreendido com todas as respostas.
Daan van Hoek #
3
Re: "Curiosity" - em unix.stackexchange.com/help/dont-ask , observe a exigência de que "Você só deve pedir práticos, perguntas respondíveis baseado em problemas reais que você enfrenta. " - que este tem sido bem recebido apesar de ter aprovado essa diretriz, é uma exceção bastante rara.
Charles Duffy
Respostas:
17
Você tem alternativas para sleep: Eles são ate cron. Ao contrário sleepdisso, é necessário que você forneça o tempo em que precisa que eles sejam executados.
Verifique se o atdserviço está sendo executado executando service atd status.
Agora, digamos que a data seja 11:17 UTC; se você precisa executar um comando às 11:25 UTC, a sintaxe é: echo "This is a test" | at 11:25.
Agora, lembre-se de que, atdpor padrão, não estará registrando a conclusão dos trabalhos. Para mais, consulte este link . É melhor que seu aplicativo tenha seu próprio log.
Você pode agendar trabalhos em cron, para mais informações, consulte: man cronpara ver suas opções ou crontab -eadicionar novos trabalhos. /var/log/cronpode ser verificado para obter informações sobre a execução nos trabalhos.
A FYI sleep system call suspende a execução atual e agenda o argumento passado a ela.
EDITAR:
Como o @Gaius mencionou, você também pode adicionar minutos para o atcomando. Mas vamos dizer que o tempo é 12:30:30e agora você executou o agendador com now +1 minutes. Mesmo que 1 minuto, que se traduz em 60 segundos, tenha sido especificado, atele não espera realmente 12:31:30para executar o trabalho, mas executa o trabalho em 12:31:00. As unidades de tempo podem ser minutes, hours, days, or weeks. Para mais informações, consulteman at
Isso não é verdade, você pode agendar uma no trabalho para dizer agora um minuto, para ser executado em um minutos de tempo
Gaius
29
Com bash builtins, você pode fazer:
coproc read -t 10&& wait "$!"|| true
Dormir por 10 segundos sem usar sleep. O coprocé fazer para que reado stdin seja um cano de onde nada saia.|| trueé porque waito status de saída refletirá uma entrega do SIGALRM, o que causaria a saída do shell se a errexitopção estiver configurada.
Em outras conchas:
mkshe ksh93tersleep embutido, não faz sentido usar qualquer outra coisa lá (embora ambos também suportem read -t).
zshtambém suporta read -t, mas também possui um wrapper interno select(), portanto você também pode usar:
@JeffSchaller Gostaria de evitá-lo, pois é um loop ocupado.
Stéphane Chazelas
@ StéphaneChazelas Eu não esperaria que isso fosse um loop ocupado - eu esperaria que qualquer shell readfosse implementado usando select (2) ou algo semelhante (o que implica que a leitura com tempo limite seria uma boa resposta para esta pergunta). Estou expressando surpresa ao invés de contradizê-lo, mas você pode apontar para uma discussão mais aprofundada sobre isso?
Norman Gray
5
@NormanGray, /dev/zeroé um arquivo que contém uma quantidade infinita de dados (NUL bytes). Então read, lerá o máximo possível durante esses 10 segundos. Felizmente, no caso de bashnão suportar armazenamento de NUL bytes em suas variáveis, isso não consumirá nenhuma memória, mas ainda consumirá os recursos da CPU.
Stéphane Chazelas
1
O @NormanGray, se executado a partir de um terminal, /dev/stdoutseria o dispositivo tty, portanto teria efeitos colaterais (como interromper o script se executado em segundo plano) e retornaria se o usuário pressionar Enter, por exemplo. read -t 10 /dev/stdout | :funcionaria no Linux, mas apenas no Linux, enquanto coprocdeveria funcionar independentemente do sistema operacional.
Stéphane Chazelas
7
Algumas outras idéias.
top -d10 -n2 >/dev/null
vmstat 102>/dev/null
sar 101>/dev/null
timeout 10s tail -f /dev/null
Você "roubou" minha ideia de limite de tempo / tempo limite .... +1
Rui F Ribeiro
1
Ohhhh meu, obrigado, eu estava em uma situação sem dormir, top é incrível!
Fire-Dragon-DoL
6
Como existem respostas sugerindo o uso da -t delayopção não padrão read, aqui está uma maneira de fazer uma leitura de tempo limite em um shell padrão:
{ ss=`stty -g`; stty -icanon min 0 time 20; read foo; stty "$ss";}
O argumento para stty timeé em décimos de segundo.
Isso faria em pausa efeito por um período que varia em algum lugar entre 9 e 10 segundos embora (devido a um bug nobash ; zshe mkshteve problemas semelhantes, mas foram corrigidos desde então)
Stéphane Chazelas
7
Uma boa maneira de fazer calor.
ctrl-alt-Delor
6
não será a primeira vez que sou acusado de estar cheio de ar quente! :)
Isso não acontecerá se o processo precisar ser executado sem interação ou em segundo plano, certo?
ss_iwe
Correto: Mas isso não era um dos requisitos do OP como pela pergunta original, por isso ainda uma resposta válida ... ;-)> :-)
Fabby
1
O OP especificamente fornece um exemplo (com sleep) e solicita uma alternativa equivalente sem. Então readnão analisa, desculpe. ;)
AnoE
A resposta de @AnoE Stéphane é, naturalmente, o melhor, o meu é apenas o mais antigo --- press «enter» to continue --- ;-)
Fabby
4
Nos dias de microcomputadores executando o BASIC, os atrasos eram geralmente realizados com um loop vazio:
FOR I = 1 TO 10000:NEXT
O mesmo princípio pode ser usado para inserir um atraso em um script de shell:
COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done
Obviamente, o problema com essa abordagem é que a duração do atraso varia de máquina para máquina de acordo com a velocidade do processador (ou mesmo na mesma máquina sob cargas diferentes). Ao contrário sleep, provavelmente também maximizará sua CPU (ou um de seus núcleos).
Loops de atraso são uma péssima idéia para qualquer coisa, exceto o mais curto sono (alguns nanossegundos ou ciclos de clock em um driver de dispositivo) em qualquer CPU moderna que possa executar um sistema operacional semelhante ao Unix. ou seja, um sono tão curto que você não pode ter utilidade para que a CPU faça outra coisa enquanto aguarda, como agendar outro processo ou entrar em um estado de sono de baixa energia antes de acordar com uma interrupção do timer. A freqüência dinâmica da CPU torna impossível calibrar um loop de atraso para contagens por segundo, exceto como um atraso mínimo, potencialmente dormindo muito mais em baixas velocidades de clock antes de aumentar.
Peter Cordes
Os computadores antigos tinham um consumo de energia muito menos dependente da carga de trabalho. As CPUs modernas precisam desligar dinamicamente partes diferentes do chip o máximo possível para não derreter (por exemplo, desligar partes das unidades de execução FPU ou SIMD enquanto apenas o código inteiro estiver em execução ou, pelo menos, bloquear o sinal do relógio nas partes do chip que não precisa ser alternado). E entrar em um estado de suspensão de baixa energia quando ocioso (em vez de girar em um loop infinito aguardando interrupções no cronômetro) também é mais recente do que os computadores antigos mencionados.
Sorry for voltando sua edição da Q: você mudou principal objetivo do PO da questão que invalidaria a resposta mais simples de todos ... ¯ \ _ (ツ) _ / ¯
Fabby
3
Um clássico da Terra do Windows e dos lotes:
ping -c 11 localhost >/dev/null && echo "This is a test"
A configuração incorreta do firewall ou do sistema de nomes pode causar um atraso adicional significativo.
espectros
1
127.0.0.1 ... @spectras
AnoE
1
Felizmente, não é mais necessário, pois o Windows agora suporta o sono nativamente.
precisa
1
@AnoE> resolve a parte do sistema de nomes, não a parte do firewall. Embora não seja comum, ele pode ser configurado para eliminar silenciosamente pings na interface local. Isso fará com que o ping aguarde muito mais tempo.
espectros
+1 para as memórias "afeiçoadas"
AC
0
Se você quiser esperar interativamente por uma nova linha em um arquivo,
tail -f
.
Esperando uma alteração em um sistema de arquivos? Então use por exemplo
inotify / inoticoming
.
E há outras opções, dependendo do que você quer dizer com "espera".
sleep
?at
pode ser um, mas não consegui encontrar nenhum exemplo de uso.Respostas:
Você tem alternativas para
sleep
: Eles sãoat
ecron
. Ao contráriosleep
disso, é necessário que você forneça o tempo em que precisa que eles sejam executados.Verifique se o
atd
serviço está sendo executado executandoservice atd status
.Agora, digamos que a data seja 11:17 UTC; se você precisa executar um comando às 11:25 UTC, a sintaxe é:
echo "This is a test" | at 11:25
.Agora, lembre-se de que,
atd
por padrão, não estará registrando a conclusão dos trabalhos. Para mais, consulte este link . É melhor que seu aplicativo tenha seu próprio log.Você pode agendar trabalhos em
cron
, para mais informações, consulte:man cron
para ver suas opções oucrontab -e
adicionar novos trabalhos./var/log/cron
pode ser verificado para obter informações sobre a execução nos trabalhos.A FYI
sleep system call
suspende a execução atual e agenda o argumento passado a ela.EDITAR:
Como o @Gaius mencionou, você também pode adicionar minutos para o
at
comando. Mas vamos dizer que o tempo é12:30:30
e agora você executou o agendador comnow +1 minutes
. Mesmo que 1 minuto, que se traduz em 60 segundos, tenha sido especificado,at
ele não espera realmente12:31:30
para executar o trabalho, mas executa o trabalho em12:31:00
. As unidades de tempo podem serminutes, hours, days, or weeks
. Para mais informações, consulteman at
por exemplo:
echo "ls" | at now +1 minutes
fonte
Com
bash
builtins, você pode fazer:Dormir por 10 segundos sem usar
sleep
. Ocoproc
é fazer para queread
o stdin seja um cano de onde nada saia.|| true
é porquewait
o status de saída refletirá uma entrega do SIGALRM, o que causaria a saída do shell se aerrexit
opção estiver configurada.Em outras conchas:
mksh
eksh93
tersleep
embutido, não faz sentido usar qualquer outra coisa lá (embora ambos também suportemread -t
).zsh
também suportaread -t
, mas também possui um wrapper internoselect()
, portanto você também pode usar:Se o que você quer é que as coisas cronograma a ser executado a partir de uma sessão de shell interativo, ver também o
zsh/sched
módulozsh
.fonte
read -t 10 < /dev/zero || true
?read
fosse implementado usando select (2) ou algo semelhante (o que implica que a leitura com tempo limite seria uma boa resposta para esta pergunta). Estou expressando surpresa ao invés de contradizê-lo, mas você pode apontar para uma discussão mais aprofundada sobre isso?/dev/zero
é um arquivo que contém uma quantidade infinita de dados (NUL bytes). Entãoread
, lerá o máximo possível durante esses 10 segundos. Felizmente, no caso debash
não suportar armazenamento de NUL bytes em suas variáveis, isso não consumirá nenhuma memória, mas ainda consumirá os recursos da CPU./dev/stdout
seria o dispositivo tty, portanto teria efeitos colaterais (como interromper o script se executado em segundo plano) e retornaria se o usuário pressionar Enter, por exemplo.read -t 10 /dev/stdout | :
funcionaria no Linux, mas apenas no Linux, enquantocoproc
deveria funcionar independentemente do sistema operacional.Algumas outras idéias.
fonte
Como existem respostas sugerindo o uso da
-t delay
opção não padrãoread
, aqui está uma maneira de fazer uma leitura de tempo limite em um shell padrão:O argumento para
stty time
é em décimos de segundo.fonte
Usando a variável interna bash
$SECONDS
e um loop ocupado:fonte
bash
;zsh
emksh
teve problemas semelhantes, mas foram corrigidos desde então)o truque mais antigo do livro:
Apenas aperte Entere continuará!
fonte
sleep
) e solicita uma alternativa equivalente sem. Entãoread
não analisa, desculpe. ;)--- press «enter» to continue ---
;-)Nos dias de microcomputadores executando o BASIC, os atrasos eram geralmente realizados com um loop vazio:
FOR I = 1 TO 10000:NEXT
O mesmo princípio pode ser usado para inserir um atraso em um script de shell:
COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done
Obviamente, o problema com essa abordagem é que a duração do atraso varia de máquina para máquina de acordo com a velocidade do processador (ou mesmo na mesma máquina sob cargas diferentes). Ao contrário
sleep
, provavelmente também maximizará sua CPU (ou um de seus núcleos).fonte
Não existe um built-in que faça o mesmo que
sleep
(a menos quesleep
esteja embutido). No entanto, existem outros comandos que aguardam.Alguns incluem.
at
ecron
: usado para agendar tarefas em um horário específico.inotifywait
: usado para aguardar um arquivo ou arquivos serem modificados / removidos / adicionados / etcfonte
at
?cron
armazenar tarefascrontab
, certo? Ondeat
armazena os dados agendados?Um clássico da Terra do Windows e dos lotes:
fonte
Se você quiser esperar interativamente por uma nova linha em um arquivo,
.Esperando uma alteração em um sistema de arquivos? Então use por exemplo
.E há outras opções, dependendo do que você quer dizer com "espera".
fonte