Dost bylo času stráveného u počítače. Je možné omezit dobu běhu procesů pomocí příkazu `timeout`. Zde je návod, jak nastavit limity pro spouštění programů s pomocí tohoto nástroje.
K čemu je příkaz timeout užitečný?
Příkaz `timeout` umožňuje definovat časový limit, po který smí běžet daný program. Proč byste to ale měli chtít dělat?
Jedním z důvodů je situace, kdy přesně víte, jak dlouho má proces běžet. Běžným příkladem je omezení doby běhu programů pro logování nebo sběr dat, aby soubory protokolů nekontrolovaně nezahlcovaly úložný prostor.
Další případ nastává, když sice nevíte, jak dlouho má proces běžet, ale zároveň nechcete, aby běžel do nekonečna. Snad máte ve zvyku spouštět procesy, minimalizovat okno terminálu a pak na ně zapomenout.
Některé programy, i ty jednoduché, mohou generovat síťový provoz v takové míře, že negativně ovlivní výkon sítě. Jiné mohou přetěžovat zdroje cílového zařízení a zpomalovat jeho chod. (Mluvím o tobě, pingu.) Nechat takové programy spuštěné bez dozoru je špatný nápad.
`timeout` je součástí sady GNU Core Utilities, takže je integrován do Linuxu a operačních systémů podobných Unixu, jako je macOS. Není potřeba nic instalovat, můžete jej používat okamžitě.
Začínáme s příkazem timeout
Zde je jednoduchý příklad. Příkaz `ping` s výchozími parametry běží, dokud jej nezastavíte klávesovou zkratkou Ctrl+C. Pokud jej neukončíte, poběží nepřetržitě.
ping 192.168.4.28
S příkazem `timeout` můžeme zabránit, aby `ping` běžel bez omezení a spotřebovával šířku pásma sítě a obtěžoval cílové zařízení.
Následující příkaz používá `timeout` k omezení doby běhu `ping`. Příkazu `ping` je povoleno běžet 15 sekund.
timeout 15 ping 192.168.4.28
Po 15 sekundách `timeout` ukončí relaci `ping` a vrátí vás do příkazového řádku.
Použití příkazu timeout s různými časovými jednotkami
Všimněte si, že jsme za hodnotu 15 nemuseli přidávat „s“. `timeout` standardně předpokládá, že hodnota je v sekundách. Můžete přidat „s“, ale není to nutné.
Pro nastavení času v minutách, hodinách nebo dnech přidejte „m“, „h“ nebo „d“.
Chcete-li, aby `ping` běžel tři minuty, použijte tento příkaz:
timeout 3m ping 192.168.4.28
`ping` poběží tři minuty, než dojde k vypršení časového limitu a relace `ping` se zastaví.
Omezení sběru dat pomocí příkazu timeout
Některé soubory se zachycenými daty mohou velmi rychle nabývat na velikosti. Abyste předešli tomu, že se tyto soubory stanou nepraktickými, nebo dokonce problematickými kvůli jejich velikosti, omezte dobu, po kterou může program pro zachycení dat běžet.
V tomto příkladu použijeme `tcpdump`, nástroj pro zachycování síťového provozu. V testovacích systémech, na kterých byl ověřován tento článek, byl `tcpdump` již nainstalován v Ubuntu Linux a Fedora Linux. V Manjaro Linux a Arch Linux bylo nutné jej nainstalovat následujícím příkazem:
sudo pacman -Syu tcpdump
Můžeme spustit `tcpdump` na 10 sekund s výchozími parametry a přesměrovat jeho výstup do souboru s názvem `capture.txt` pomocí tohoto příkazu:
timeout 10 sudo tcpdump > capture.txt
Co se stalo? Proč příkaz `timeout` nezastavil `tcpdump`?
Vše souvisí se signály.
Odeslání správného signálu
Když chce `timeout` zastavit program, odešle signál SIGTERM. Tím zdvořile požádá program o ukončení. Některé programy se však mohou rozhodnout signál SIGTERM ignorovat. V takovém případě musíme příkazu `timeout` dát vědět, že má být důraznější.
Můžeme to provést tak, že `timeout` požádáme o odeslání signálu SIGKILL.
Signál SIGKILL nelze „zachytit, zablokovat ani ignorovat“ – vždy projde. SIGKILL program nezdvořile žádá o zastavení. SIGKILL čeká za rohem s budíkem a obuškem.
Volbu `-s` (signál) můžeme použít k určení signálu SIGKILL pro `timeout`.
timeout -s SIGKILL 10 sudo tcpdump > capture.txt
Nejdříve zdvořilá žádost
Můžeme požádat `timeout`, aby se nejdříve pokusil zastavit program pomocí SIGTERM, a teprve pokud by to nefungovalo, použít signál SIGKILL.
K tomu použijeme volbu `-k` (kill after). Volba `-k` vyžaduje časovou hodnotu jako parametr.
V tomto příkazu požadujeme, aby `dmesg` běžel po dobu 30 sekund a poté byl ukončen signálem SIGTERM. Pokud `dmesg` stále běží po 40 sekundách, znamená to, že diplomatický signál SIGTERM byl ignorován a příkaz `timeout` by měl použít signál SIGKILL k dokončení úkolu.
`dmesg` je nástroj, který umožňuje monitorovat zprávy kruhové vyrovnávací paměti jádra a zobrazovat je v okně terminálu.
timeout -k 40 30 dmesg -w
`dmesg` běží 30 sekund a zastaví se, když obdrží signál SIGTERM.
Víme, že `dmesg` nezastavil SIGKILL, protože SIGKILL vždy zanechá v okně terminálu jednoslovný nekrolog: „Killed“. V tomto případě se tak nestalo.
Získání výstupního kódu programu
Správně fungující programy předají při ukončení zpět do shellu hodnotu. Toto je známé jako výstupní kód. Obvykle se používá k informování shellu, nebo jakéhokoli procesu, který program spustil, zda během běhu nastaly problémy.
Příkaz `timeout` má svůj vlastní výstupní kód, ale ten nás možná nezajímá. Pravděpodobně nás více zajímá výstupní kód z procesu, který `timeout` kontroluje.
Tento příkaz spustí `ping` na pět sekund. Pinguje počítač s názvem Nostromo, který je v testovací síti použité pro tento článek.
timeout 5 ping Nostromo.local
Příkaz běží pět sekund a `timeout` jej ukončí. Poté můžeme zkontrolovat výstupní kód pomocí tohoto příkazu:
echo $?
Výstupní kód je 124. Tuto hodnotu používá `timeout` k označení programu, který byl ukončen pomocí signálu SIGTERM. Pokud program ukončí signál SIGKILL, výstupní kód je 137.
Pokud program přerušíme pomocí Ctrl+C, výstupní kód z `timeout` je nula.
timeout 5 ping Nostromo.local
echo $?
Pokud se program ukončí dříve, než ho zastaví příkaz `timeout`, může `timeout` předat výstupní kód z programu zpět do shellu.
Aby se tak stalo, program se musí zastavit sám (jinými slovy, nesmí být ukončen příkazem `timeout`) a musíme použít volbu `–preserve-status`.
Pokud použijeme volbu `-c` (count) s hodnotou pět, odešle se pouze pět požadavků. Pokud `timeout` nastavíme na dobu trvání jedné minuty, `ping` se zcela jistě ukončí sám. Poté můžeme zkontrolovat výstupní hodnotu pomocí `echo`.
timeout --preserve-status 1m ping -c 5 Nostromo.local
echo $?
`ping` dokončí pět požadavků a ukončí se. Výstupní kód je nula.
Chceme-li ověřit, že výstupní kód pochází z příkazu `ping`, vynutíme, aby `ping` vygeneroval jiný ukončovací kód. Pokud se pokusíme odeslat požadavky `ping` na neexistující IP adresu, `ping` selže s chybovým ukončovacím kódem. Poté můžeme pomocí `echo` zkontrolovat, že výstupní kód není nulový.
timeout --preserve-status 1m ping -c 5 NotHere.local
echo $?
Příkaz `ping` se zjevně nemůže připojit k neexistujícímu zařízení, takže ohlásí chybu a ukončí se. Výstupní kód je dva. Toto je výstupní kód, který `ping` používá pro obecné chyby.
Nastavení základních pravidel
Příkaz `timeout` slouží k nastavení určitých hranic pro spouštěné programy. Pokud hrozí, že soubory protokolu zahlcují pevný disk, nebo že zapomenete na spuštěný síťový nástroj, použijte příkaz `timeout` a nechte počítač, ať se sám reguluje.