Jak spać przez milisekundę w bash lub ksh

128

sen jest bardzo popularnym poleceniem i możemy zacząć spać od 1 sekundy:

# wait one second please 
sleep 1

ale jaka alternatywa, jeśli muszę czekać tylko 0,1 sekundy lub od 0,1 do 1 sekundy?

  • Uwaga: na Linuksie lub OS X sleep 0.XXXdziała dobrze, ale na Solaris sleep 0.1lub sleep 0.01- Nielegalna składnia
Yael
źródło
2
Czy mogę zapytać, dlaczego chcesz spać przez 1ms?
Tom O'Connor,
1
Tak, oczywiście, w moim skrypcie bash dodałem „sleep 1”, w niektórych liniach, ale skrypt działa bardzo wolno, więc po pewnych wnioskach obliczyłem, że sen 0.1 przynosi również dobre wyniki i jest szybszy O opóźnieniu potrzebuję opóźnienia aby rozwiązać problem ssh w moim skrypcie bash, wykonuję równoległe logowanie ssh do niektórych maszyn przez oczekiwanie i bezzwłocznie jego nie zadziała, jak wiecie z mojego pytania, opóźnienie powinno pasować zarówno do Linuksa, jak i do Solaris
yael
3
Niezależnie od wybranego rozwiązania pamiętaj, że skrypt powłoki nie będzie zbyt dokładny pod względem czasu.
scai 15.01.2013
Co powiesz na zrobienie czegoś, co wymaga bardzo krótkiego czasu, ale nic nie robi ... jakecho "" >/dev/null
Tom O'Connor
Dobry pomysł, ale jak msc to polecenie? , Potrzebuję 0,1 ms, nie mniej niż to - :)
yael

Odpowiedzi:

68

Bash ma „ładowany” sen, który obsługuje ułamkowe sekundy i eliminuje koszty zewnętrzne polecenia:

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

Następnie:

$ 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

Minusem jest to, że pliki ładowalne mogą nie być dostarczane z Twoim bashplikiem binarnym, więc musisz sam je skompilować, jak pokazano (chociaż w Solarisie nie musi to być tak proste, jak powyżej).

Odbash-4.4 (wrzesień 2016 r.) Wszystkie programy ładujące są teraz budowane i instalowane domyślnie na platformach, które je obsługują, chociaż są one budowane jako osobne pliki obiektów współużytkowanych i bez .soprzyrostka. O ile Twój system / system operacyjny nie zrobił czegoś kreatywnego, powinieneś być w stanie to zrobić:

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

(Strona BASH_LOADABLES_PATHpodręcznika sugeruje, że jest ustawiana automatycznie, uważam, że nie jest tak w oficjalnej dystrybucji od 4.4.12. Jeśli i kiedy jest ustawiona poprawnie, potrzebujesz tylko enable -f filename commandnamezgodnie z wymaganiami.)

Jeśli to nie jest odpowiednie, następną najłatwiejszą rzeczą jest zbudowanie lub uzyskanie sleepz GNU coreutils, obsługuje to wymaganą funkcję. Polecenie POSIX sleepjest minimalne, starsze wersje systemu Solaris zaimplementowały tylko to. Solaris 11 sleep nie obsługują ułamków sekund.

W ostateczności możesz użyć perl(lub dowolnego innego skryptu, który masz pod ręką) z zastrzeżeniem, że inicjowanie interpretera może być porównywalne z zamierzonym czasem snu:

$ perl -e "select(undef,undef,undef,0.1);"
$ echo "after 100" | tclsh
pan. spuratic
źródło
2
Ach, skoro używasz expect, prawdopodobnie możesz po prostu użyć „ after N”, gdzie N to milisekundy, bezpośrednio w skrypcie.
mr. Spuratic
użyj usleepjak @Luis Vazquez i @sebix pisz
Ilan.K
Apple MacOS ma
tryb
125

Dokumentacja sleeppolecenia z coreutils mówi:

Historyczne implementacje uśpienia wymagały, aby liczba ta była liczbą całkowitą i zaakceptowała tylko jeden argument bez przyrostka. Jednak GNU sleep akceptuje dowolne liczby zmiennoprzecinkowe. Zobacz zmiennoprzecinkowy .

Stąd można użyć sleep 0.1, sleep 1.0e-1i podobne argumenty.

scai
źródło
1
zobacz moją uwagę na temat systemu operacyjnego SOLARIS
yael 15.01.13
Czy mieszać to i nie jest ?
scai
zobacz moją aktualizację w moim
pytaniu
1
Yael, myślę, że w twoim pytaniu wciąż jest za dużo negatywów; czy na pewno masz na myśli „nie nielegalną składnię”?
MadHatter
na przykład - uruchamiam na solaris 10 to: # sen 0,1 sen: zły znak w kłótni, o linux sen 0,1 działa dobrze
yael
58

Tryb uśpienia akceptuje liczby dziesiętne, dzięki czemu możesz go podzielić w następujący sposób:

1/2 sekundy

 sleep 0.5

1/100 sekundy

sleep 0.01

Więc przez milisekundę chciałbyś

sleep 0.001
colealtdelete
źródło
4
Możesz także upuścić wiodące zero przed przecinkiem. na przykład. sleep .5
Mike Causer
Porozmawiaj o tym, że wszyscy to komplikują ...
Martin
1
@MikeCauser wiodące zera są znacznie bardziej czytelne i sygnalizują zamiar czytelnikowi kodu później. także lepiej, kiedy faktycznie robisz matematykę.
Alexander Mills,
11

Spróbuj tego, aby określić dokładność:

    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)

Połączenie rozwiązania mr.spuratic za i rozwiązania Coles męska .

dsrdakota
źródło
8

Możesz po prostu użyć usleep. Jako parametr potrzeba mikrosekund (= 1e-6 sekund), więc aby spać 1 milisekundę, wpisz:

usleep 1000
Luis Vazquez
źródło
1
$ usleep No command 'usleep' found, did you mean: Command 'sleep' from package 'coreutils' (main) usleep: command not found
Bulletmagnet
Nie, mam na myśli usleepczęść initscriptspakietu, która jest standardowa przynajmniej we wszystkich dystrybucjach pochodzących od Red Hata; w tym co najmniej RHEL, CentOS, Fedora, Mageia / Mandriva i SuSE. Oto przykład: ``
Luis Vazquez
1
Oto przykładowa ilustracja uruchomiona w CentOS 7: `` $ usleep / usr / bin / usleep $ rpm -qf / usr / bin / usleep initscripts-9.49.37-1.el7_3.1.x86_64 `` Podsumowując : - sleep(z coreutils ) działa z sekundami - usleep(z skryptów startowych ) działa z mikro-sekundami
Luis Vazquez
4

Miałem ten sam problem (brak snu w Solarisie), więc napisałem swój w ten sposób:

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

Nie sprawdza argumentów - polecam poprawnie napisany, jeśli chcesz go zachować, ale to (gcc usleep.c -o usleep) wyciągnie cię z dziury.

Jrichemont
źródło
1
Możesz przynajmniej zmienić to puste usleep()połączenie, aby if(argc == 1) { usleep(atoi(argv[1])); }uniknąć indeksowania poza granicami tablicy, co może prowadzić do dowolnej liczby nieoczekiwanych zachowań.
CVn
@aCVn To właściwie if (argc == 2) { usleep(atoi(argv[1])); }...
Pierścień Ø
Zauważ też, że usleepjednostką jest μs, więc aby poczekać 1 sekundę, musisz podać argument 1000000.
Pierścień Ø
@ Pierścień Ø Prawo. Głupi błąd, dobry chwyt.
CVn
atoi()jest okropnym wyborem do konwersji łańcucha na int. Co atoi( "STRING" )zwraca atoi()nie ma możliwości zwrócenia żadnego błędu.
Andrew Henle