Używam startx
do uruchamiania X, który oceni mój .xinitrc
. W moim .xinitrc
uruchamiam menedżera okien za pomocą /usr/bin/mywm
. Teraz, jeśli zabiję mojego WM (aby np. Przetestować inny WM), X również zakończy działanie, ponieważ .xinitrc
skrypt osiągnął EOF. Więc dodałem to na końcu mojego .xinitrc
:
while true; do sleep 10000; done
W ten sposób X nie wyłączy się, jeśli zabiję mojego WM. Teraz moje pytanie: jak mogę spać w nieskończoność zamiast snu w pętli? Czy jest jakaś komenda, która trochę zamrozi skrypt?
Z poważaniem
sleep infinity
, chociaż fajnie było się o tym dowiedzieć dla Linuksa. Jednakwhile true; do sleep 86400; done
powinno być substytutem.infinity
jest konwertowane w C z „string” do adouble
. Następniedouble
jest to obcinane do maksymalnych dozwolonych wartościtimespec
, co oznacza bardzo dużą liczbę sekund (zależnych od architektury), ale w teorii skończoną.tail
nie blokujeJak zawsze: na wszystko jest odpowiedź, która jest krótka, łatwa do zrozumienia, łatwa do zrozumienia i całkowicie błędna. Tutaj
tail -f /dev/null
należy do tej kategorii;)Jeśli spojrzysz na to razem
strace tail -f /dev/null
, zauważysz, że to rozwiązanie jest dalekie od blokowania! Prawdopodobnie jest jeszcze gorsze niżsleep
rozwiązanie w pytaniu, ponieważ wykorzystuje (pod Linuksem) cenne zasoby, takie jakinotify
system. Również inne procesy, które piszą, aby/dev/null
zrobićtail
pętlę. (Na moim Ubuntu64 16.10 dodaje to kilka 10 wywołań systemowych na sekundę w już zajętym systemie).Pytanie dotyczyło polecenia blokującego
Niestety nie ma czegoś takiego.
Przeczytaj: Nie znam sposobu, aby zarchiwizować to bezpośrednio w powłoce.
Wszystko (nawet
sleep infinity
) może zostać przerwane jakimś sygnałem. Więc jeśli chcesz być naprawdę pewien, że nie zwróci się wyjątkowo, musi działać w pętli, tak jak już to zrobiłeś dla twojegosleep
. Należy pamiętać, że (w systemie Linux)/bin/sleep
najwyraźniej jest ograniczony do 24 dni (spójrzstrace sleep infinity
), dlatego najlepsze, co możesz zrobić, to prawdopodobnie:(Zauważ, że uważam, że
sleep
pętle są wewnętrznie pętle dla wartości wyższych niż 24 dni, ale to oznacza: nie blokuje, tylko bardzo powoli się zapętla. Dlaczego więc nie przenieść tej pętli na zewnątrz?).. ale możesz podejść całkiem blisko z nienazwanym
fifo
Możesz stworzyć coś, co naprawdę blokuje, o ile nie ma sygnałów wysyłanych do procesu. Następujące zastosowania
bash 4
, 2 PID i 1fifo
:Możesz sprawdzić, czy to naprawdę blokuje,
strace
jeśli chcesz:Jak to zostało skonstruowane
read
blokuje się, jeśli nie ma danych wejściowych (zobacz inne odpowiedzi). Jednaktty
(aka.stdin
) Zwykle nie jest dobrym źródłem, ponieważ jest zamykane, gdy użytkownik się wylogowuje. Może również ukraść część danych wejściowych ztty
. Niemiły.Aby utworzyć
read
blok, musimy poczekać na coś takiego,fifo
co nigdy nie zwróci niczego. Wbash 4
nie jest poleceniem, które mogą dostarczyć nam dokładnie z takąfifo
:coproc
. Jeśli również poczekamy na blokowanieread
(które jest naszecoproc
), skończymy. Niestety wymaga to otwarcia dwóch identyfikatorów PID i plikufifo
.Wariant z nazwanym
fifo
Jeśli nie zawracasz sobie głowy używaniem nazwanego
fifo
, możesz to zrobić w następujący sposób:Nieużywanie pętli przy odczycie jest trochę niechlujne, ale możesz użyć tego ponownie
fifo
tak często, jak chcesz i sprawić, żeread
s terminat zostanie użytytouch "$HOME/.pause.fifo"
(jeśli czeka więcej niż jeden odczyt, wszystkie są przerywane jednocześnie).Lub użyj
pause()
wywołania systemowego LinuxW przypadku nieskończonego blokowania istnieje wywołanie jądra Linuksa, o nazwie
pause()
, które robi to, co chcemy: Czekaj wiecznie (aż nadejdzie sygnał). Jednak nie ma do tego (jeszcze) programu przestrzeni użytkownika.do
Stworzenie takiego programu jest łatwe. Oto fragment stworzyć bardzo mały program o nazwie Linux
pause
, który wstrzymuje na czas nieokreślony (potrzebdiet
,gcc
etc.):python
Jeśli nie chcesz samemu kompilować czegoś, ale masz już
python
zainstalowany, możesz użyć tego pod Linuksem:(Uwaga: użyj
exec python -c ...
do zastąpienia bieżącej powłoki, zwalnia to jeden PID. Rozwiązanie można również ulepszyć za pomocą niektórych przekierowań we / wy, zwalniając nieużywane FD. To zależy od Ciebie.)Jak to działa (chyba):
ctypes.CDLL(None)
ładuje standardową bibliotekę C i uruchamiapause()
w niej funkcję w ramach dodatkowej pętli. Mniej wydajna niż wersja C, ale działa.Moja rekomendacja dla Ciebie:
Pozostań w zapętlonym śnie. Jest łatwy do zrozumienia, bardzo przenośny i przez większość czasu blokuje.
źródło
trap
(które modyfikuje zachowanie powłoki na sygnały) ani tła (które pozwala powłoce przechwytywać sygnały z terminala, jak Strg + C). Więcsleep infinity
wystarczy (zachowuje się tak,exec sleep infinity
jakby to była ostatnia instrukcja. Aby zobaczyć różnicę użyjstrace -ffDI4 bash -c 'YOURCODEHERE'
). Zapętlony sen jest lepszy, ponieważsleep
w pewnych okolicznościach może powrócić. Na przykład nie chcesz, aby X11 nagle się wyłączyłkillall sleep
, tylko dlatego, że zamiast pętli uśpienia.xstartup
kończysleep infinity
się.s6-pause
jest to polecenie użytkownika do uruchomieniapause()
, opcjonalnie ignorujące różne sygnały./bin/sleep
nie jest ograniczone do 24 dni, jak mówisz. Byłoby miło, gdybyś mógł to zaktualizować. Obecnie w systemie Linux ten kod jest aktywny. Ogranicza pojedynczenanosleep()
wywołania systemowe do 24 dni, ale wywołuje je w pętli. Więcsleep infinity
nie powinien wychodzić po 24 dniach.double
Dodatni nieskończoność zostaje przekształca się wstruct timespec
. Patrząc narpl_nanosleep
GDB,infinity
zostaje przekonwertowany{ tv_sec = 9223372036854775807, tv_nsec = 999999999 }
na Ubuntu 16.04.strace
sam nie mogę udowodnić, że naprawdę jest wkompilowany kod zapętlającysleep
, i nie chcę czekać 24 dni tylko na przetestowanie tego (lub dekompilację/bin/sleep
). Zawsze lepiej jest programować defensywnie, jeśli nie ma twardego matematycznego dowodu, że coś jest naprawdę takie, jakim się wydaje. Nigdy też niczego nie ufaj:killall -9 sleep
Może wydaje się to brzydkie, ale dlaczego nie po prostu biegać
cat
i czekać na wejście w nieskończoność?źródło
cat
to?mkfifo pipe && cat pipe
TL; DR:
sleep infinity
faktycznie przesypia maksymalny dozwolony czas, który jest skończony.Zastanawiając się, dlaczego nie jest to nigdzie udokumentowane, zadałem sobie trud przeczytania źródeł z coreutils GNU i stwierdziłem, że wykonuje z grubsza to, co następuje:
strtod
z C stdlib na pierwszym argumencie, aby przekonwertować „nieskończoność” na podwójną precyzję. Tak więc, zakładając podwójną precyzję IEEE 754, 64-bitowa dodatnia wartość nieskończoności jest przechowywana wseconds
zmiennej.xnanosleep(seconds)
( znajdujący się w gnulib ), to z kolei wywołujedtotimespec(seconds)
( również w gnulib ) do konwersji zdouble
nastruct timespec
.struct timespec
to po prostu para liczb: część całkowita (w sekundach) i część ułamkowa (w nanosekundach). Naiwna zamiana dodatniej nieskończoności na liczbę całkowitą spowodowałaby niezdefiniowane zachowanie (patrz §6.3.1.4 standardu C), więc zamiast tego skraca się doTYPE_MAXIMUM (time_t)
.TYPE_MAXIMUM (time_t)
nie jest ustawiona w standardzie (nawetsizeof(time_t)
nie jest); więc dla przykładu wybierzmy x86-64 z ostatniego jądra Linuksa.To jest
TIME_T_MAX
w jądrze Linuksa, które jest zdefiniowane (time.h
) jako:Zauważ, że
time_t
jest__kernel_time_t
itime_t
jestlong
; używany jest model danych LP64, więcsizeof(long)
8 (64 bity).Skutkiem czego jest:
TIME_T_MAX = 9223372036854775807
.To znaczy:
sleep infinite
daje w wyniku rzeczywisty czas snu 9223372036854775807 sekund (10 ^ 11 lat). A dla 32-bitowych systemów linuxowych (sizeof(long)
to 4 (32 bity)): 2147483647 sekund (68 lat; zobacz także problem z rokiem 2038 ).Edycja : najwyraźniej
nanoseconds
wywołana funkcja nie jest bezpośrednio wywołaniem syscall, ale opakowaniem zależnym od systemu operacyjnego (również zdefiniowanym w gnulib ).Jest to dodatkowy krok w wyniku: na niektórych systemach, gdzie
HAVE_BUG_BIG_NANOSLEEP
jesttrue
sen jest obcięty do 24 dni, a następnie wezwał w pętli. Dzieje się tak w przypadku niektórych (lub wszystkich?) Dystrybucji Linuksa. Zauważ, że to opakowanie może nie być używane, jeśli test w czasie konfiguracji zakończy się pomyślnie ( źródło ).W szczególności byłoby to
24 * 24 * 60 * 60 = 2073600 seconds
(plus 999999999 nanosekund); ale jest to wywoływane w pętli w celu uwzględnienia określonego całkowitego czasu snu. Dlatego poprzednie wnioski pozostają aktualne.Podsumowując, wynikający z tego czas snu nie jest nieskończony, ale wystarczająco długi dla wszystkich praktycznych celów , nawet jeśli wynikający z tego faktyczny upływ czasu nie jest przenośny; to zależy od systemu operacyjnego i architektury.
Aby odpowiedzieć na pierwotne pytanie, jest to oczywiście wystarczająco dobre, ale jeśli z jakiegoś powodu (system o bardzo ograniczonych zasobach) naprawdę chcesz uniknąć bezużytecznego dodatkowego licznika czasu, wydaje mi się, że najbardziej poprawną alternatywą jest użycie
cat
metody opisanej w innych odpowiedziach .źródło
sleep infinity
będzie teraz spać wiecznie bez zapętlania: lists.gnu.org/archive/html/bug-gnulib/2020-02/msg00081.htmlsleep infinity
wygląda najbardziej elegancko, ale czasami z jakiegoś powodu nie działa. W takim przypadku można spróbować innych poleceń blokowania takich jakcat
,read
,tail -f /dev/null
,grep a
itdźródło
tail -f /dev/null
było również działającym rozwiązaniem dla mnie na platformie SaaStail -f /dev/null
ma również tę zaletę, że nie zużywa stdin. Użyłem go z tego powodu.A co z wysłaniem SIGSTOP- a do siebie?
Powinno to wstrzymać proces do momentu odebrania SIGCONT. Tak jest w twoim przypadku: nigdy.
źródło
Pozwólcie, że wyjaśnię, dlaczego
sleep infinity
działa, chociaż nie jest to udokumentowane. Odpowiedź jp48 jest również przydatna.Najważniejsze: określając
inf
lubinfinity
(bez rozróżniania wielkości liter) możesz spać najdłużej, na co pozwala implementacja (tj. Mniejsza wartośćHUGE_VAL
iTYPE_MAXIMUM(time_t)
).Przejdźmy teraz do szczegółów. Kod źródłowy
sleep
polecenia można odczytać z coreutils / src / sleep.c . Zasadniczo funkcja robi to:Zrozumienie
xstrtod (argv[i], &p, &s, cl_strtod)
xstrtod()
Zgodnie z gnulib / lib / xstrtod.c , wywołanie funkcji
xstrtod()
konwertuje ciąg znakówargv[i]
na wartość zmiennoprzecinkową i zapisuje ją do niej*s
przy użyciu funkcji konwertującejcl_strtod()
.cl_strtod()
Jak widać z coreutils / lib / cl-strtod.c ,
cl_strtod()
konwertuje ciąg znaków na wartość zmiennoprzecinkową, używającstrtod()
.strtod()
Według
man 3 strtod
,strtod()
konwertuje ciąg znaków do wartości typudouble
. Strona podręcznika mówia nieskończoność definiuje się jako
Chociaż dokument mówi
, nie jest jasne, jak traktuje się nieskończoność. Zobaczmy więc kod źródłowy gnulib / lib / strtod.c . To, co chcemy przeczytać, to
Dlatego
INF
iINFINITY
(bez rozróżniania wielkości liter) są traktowane jakoHUGE_VAL
.HUGE_VAL
rodzinaUżyjmy N1570 jako standardu C.
HUGE_VAL
,HUGE_VALF
aHUGE_VALL
makra są zdefiniowane w §7.12-3oraz w §7.12.1-5
Zrozumienie
xnanosleep (s)
Teraz rozumiemy całą istotę
xstrtod()
. Z powyższych wyjaśnień jasno wynikaxnanosleep(s)
, że widzieliśmy najpierw faktycznie oznaczaxnanosleep(HUGE_VALL)
.xnanosleep()
Zgodnie z kodem źródłowym gnulib / lib / xnanosleep.c ,
xnanosleep(s)
zasadniczo robi to:dtotimespec()
Ta funkcja konwertuje argument typu
double
na obiekt typustruct timespec
. Ponieważ jest to bardzo proste, zacytuję kod źródłowy gnulib / lib / dtotimespec.c . Wszystkie komentarze są dodawane przeze mnie.Ponieważ
time_t
jest zdefiniowany jako typ całkowity (patrz §7.27.1-3), jest naturalne, że zakładamy, że maksymalna wartość typutime_t
jest mniejsza niżHUGE_VAL
(typudouble
), co oznacza, że wchodzimy w przypadek przepełnienia. (W rzeczywistości założenie to nie jest potrzebne, ponieważ we wszystkich przypadkach procedura jest zasadniczo taka sama).make_timespec()
Ostatnia ściana, na którą musimy się wspiąć, to
make_timespec()
. Na szczęście jest to tak proste, że wystarczy przytoczyć kod źródłowy gnulib / lib / timespec.h .źródło
Niedawno musiałem to zrobić. Wymyśliłem następującą funkcję, która pozwoli bashowi spać wiecznie bez wywoływania żadnego zewnętrznego programu:
UWAGA: Wcześniej opublikowałem wersję tego, która otwierała i zamykała deskryptor pliku za każdym razem, ale odkryłem, że w niektórych systemach zrobienie tego setki razy na sekundę w końcu blokowało się. W ten sposób nowe rozwiązanie zachowuje deskryptor pliku między wywołaniami funkcji. Bash i tak posprząta przy wyjściu.
Można to nazwać podobnie jak / bin / sleep i będzie spać przez żądany czas. Nazywany bez parametrów, zawiesi się na zawsze.
Na moim blogu jest napis z nadmierną ilością szczegółów
źródło
Takie podejście nie pochłonie żadnych zasobów do podtrzymania procesu.
while :; do sleep 1; done & kill -STOP $! && wait $!
Awaria
while :; do sleep 1; done &
Tworzy fikcyjny proces w tlekill -STOP $!
Zatrzymuje proces w tlewait $!
Poczekaj na proces w tle, będzie to blokować na zawsze, ponieważ proces w tle został wcześniej zatrzymanyźródło
Zamiast zabijać menedżera okien, spróbuj uruchomić nowy z
--replace
lub,-replace
jeśli jest dostępny.źródło
--replace
, zawsze otrzymuję ostrzeżenie typuanother window manager is already running
. To nie ma dla mnie większego sensu.bez czekania na sen dziecka.
źródło
stdin
jeśli nadal jest podłączony dotty
. Jeśli uruchomisz go za pomocą< /dev/null
zajętych pętli. Może się to przydać w pewnych sytuacjach, więc nie głosuję przeciw.