Como durmo um milissegundo em bash ou ksh

128

sleep é um comando muito popular e podemos começar a dormir a partir de 1 segundo:

# wait one second please 
sleep 1

mas qual a alternativa se eu precisar esperar apenas 0,1 segundo ou entre 0,1 a 1 segundo?

  • observação: no linux ou no OS X sleep 0.XXXfunciona bem, mas no solaris sleep 0.1ou sleep 0.01- sintaxe ilegal
yael
fonte
2
Posso perguntar por que você quer dormir por 1ms?
Tom O'Connor
1
Sim, é claro, no meu script bash eu adiciono "sleep 1", em algumas linhas, mas o script é executado muito lentamente, então, após alguma conclusão, calculo que o sleep 0.1 também trará bons resultados e mais rápido Sobre o atraso, preciso de um atraso para para resolver o problema ssh no meu script bash, eu executo o login ssh paralelo para algumas máquinas de esperar e sem demora o seu não vai funcionar, Como você sabe da minha pergunta o atraso deve caber Linux e Solaris
yael
3
Qualquer que seja a solução que você escolher, lembre-se de que um script de shell não será muito preciso em termos de tempo.
Scai
Que tal fazer algo que leva um tempo muito curto para ser executado, mas não faz nada .. comoecho "" >/dev/null
Tom O'Connor
Boa ideia, mas como msec este comando leva? , Eu preciso de 0,1 ms, e não menos, então, que - :)
yael

Respostas:

68

O Bash tem um sono "carregável" que suporta segundos fracionários e elimina as despesas gerais de um comando externo:

$ cd bash-3.2.48/examples/loadables
$ make sleep && mv sleep sleep.so
$ enable -f sleep.so sleep

Então:

$ which sleep
/usr/bin/sleep
$ builtin sleep
sleep: usage: sleep seconds[.fraction]
$ time (for f in `seq 1 10`; do builtin sleep 0.1; done)
real    0m1.000s
user    0m0.004s
sys     0m0.004s

A desvantagem é que os carregáveis ​​podem não ser fornecidos com o seu bashbinário, portanto você precisará compilá-los como mostrado (embora no Solaris não seja necessariamente tão simples como acima).

A partir debash-4.4 (setembro de 2016), todos os carregáveis ​​agora são construídos e instalados por padrão nas plataformas que o suportam, embora sejam construídos como arquivos de objetos compartilhados separados e sem .sosufixo. A menos que sua distribuição / SO tenha feito algo criativo, você poderá fazer:

[ -z "$BASH_LOADABLES_PATH" ] &&
  BASH_LOADABLES_PATH=$(pkg-config bash --variable=loadablesdir 2>/dev/null)  
enable -f sleep sleep

(A página de manual implica que ela BASH_LOADABLES_PATHseja configurada automaticamente, acho que esse não é o caso na distribuição oficial a partir de 4.4.12. Se e quando estiver configurada corretamente, você precisará apenas enable -f filename commandnameconforme necessário.)

Se isso não for adequado, a próxima coisa mais fácil a fazer é criar ou obter sleepdo GNU coreutils, isso suporta o recurso necessário. O sleepcomando POSIX é mínimo, versões mais antigas do Solaris implementadas apenas isso. Solaris 11 sleep faz apoiar segundos fracionários.

Como último recurso, você pode usar perl(ou qualquer outro script que tenha em mãos) com a ressalva de que a inicialização do intérprete pode ser comparável ao tempo de sono pretendido:

$ perl -e "select(undef,undef,undef,0.1);"
$ echo "after 100" | tclsh
mr.spuratic
fonte
2
Ah, como você está usando, expectprovavelmente pode usar " after N", onde N é milissegundos, diretamente no seu script.
precisa saber é o seguinte
usar usleepcomo @Luis Vazquez e escrever @sebix
Ilan.K
Apple MacOS tem suspensão BSD, que também suporta segundos fracionários
roblogic
125

A documentação para o sleepcomando do coreutils diz:

As implementações históricas do sono exigiram que o número fosse um número inteiro e só aceitaram um único argumento sem sufixo. No entanto, o sono GNU aceita números arbitrários de ponto flutuante. Consulte Ponto flutuante .

Daí você pode usar sleep 0.1, sleep 1.0e-1e argumentos semelhantes.

scai
fonte
1
veja minha observação sobre o SOLARIS OS
yael
Você misturou é e não é ?
Scal
veja minha atualização no meu quastion
yael
1
Yael, acho que ainda há muitos pontos negativos na sua pergunta; tem certeza de que quer dizer "sintaxe não ilegal"?
MadHatter
por exemplo - eu corro no solaris 10 isto: # sono 0.1 sono: caractere ruim no argumento, sobre o sono linux 0.1 funciona bem
yael
58

O modo de suspensão aceita números decimais para que você possa decompô-lo da seguinte maneira:

1/2 de segundo

 sleep 0.5

1/100 de segundo

sleep 0.01

Então, por um milissegundo, você gostaria

sleep 0.001
colealtdelete
fonte
4
Você também pode soltar o zero inicial antes do ponto decimal. por exemplo. sleep .5
Mike Causador
Fale sobre todos os outros complicar-lo ...
Martin
1
Os zeros à esquerda do @MikeCauser são muito mais legíveis e sinalizam a intenção para o leitor do código posteriormente. também melhor quando você realmente faz contas.
Alexander Mills
11

Tente isso para determinar a precisão:

    time sleep 0.5      # 500 milliseconds (1/2 of a second)
    time sleep 0.001    # 1 millisecond (1/1000 of a second)
    time sleep 1.0      # 1 second (1000 milliseconds)

Combinação de solução de mr.spuratic e solução de Coles .

dsrdakota
fonte
8

Você pode simplesmente usar usleep. Leva microssegundos (= 1e-6 segundos) como parâmetro; portanto, para dormir 1 milissegundo, você deve digitar:

usleep 1000
Luis Vazquez
fonte
1
$ usleep No command 'usleep' found, did you mean: Command 'sleep' from package 'coreutils' (main) usleep: command not found
Bulletmagnet
Não, quero dizer usleepparte do initscriptspacote, que é padrão pelo menos em todas as distribuições derivadas da Red Hat; incluindo pelo menos RHEL, CentOS, Fedora, Mageia / Mandriva e SuSE. Aqui está um exemplo: `` ``
Luis Vazquez
1
Aqui está uma ilustração de exemplo em execução no CentOS 7: `` $ what usleep / usr / bin / usleep $ rpm -qf / usr / bin / usleep initscripts-9.49.37-1.el7_3.1.x86_64 `` `Para resumir : - sleep(do coreutils ) trabalha com segundos - usleep(do initscripts ) trabalha com micro segundos
Luis Vazquez
4

Eu tive o mesmo problema (sem uso de shell no Solaris), então escrevi o meu da seguinte maneira:

  #include "stdio.h"
  int main(int argc, char **argv) {
     if(argc == 2) { usleep(atoi(argv[1])); }
     return 0;
}

Não verifica argumentos - eu recomendaria um escrito corretamente se você quisesse mantê-lo, mas que (gcc usleep.c -o usleep) o tirará de um buraco.

jrichemont
fonte
1
Você pode pelo menos alterar essa usleep()chamada simples if(argc == 1) { usleep(atoi(argv[1])); }para evitar a indexação fora dos limites da matriz, o que pode levar a qualquer número de comportamentos inesperados.
um CVn
@aCVn Na verdade é if (argc == 2) { usleep(atoi(argv[1])); }...
Anel Ø
Observe também que a usleepunidade é μs; portanto, para aguardar 1 segundo, é necessário fornecer um argumento 1000000.
Anel Ø
@ RingØ Certo. Erro estúpido, boa captura.
um CVn 26/03
atoi()é uma escolha horrível para converter uma string em um int. O que atoi( "STRING" )retorna? atoi()não tem como retornar nenhum erro.
Andrew Henle