Bine, e timpul să luăm o pauză de la calculator. Pentru a controla durata de funcționare a proceselor, comanda `timeout` este perfectă, permițându-ți să stabilești un interval maxim de timp. Vom explora cum să gestionezi timpul de execuție al programelor cu ajutorul acestei comenzi.
Ce face comanda timeout pentru tine?
Comanda `timeout` te ajută să limitezi timpul alocat unui program. Dar de ce ai avea nevoie de o astfel de funcționalitate?
Un scenariu tipic este atunci când știi exact cât timp vrei să ruleze un proces. De exemplu, poți controla timpul de funcționare al unui program de înregistrare a datelor, astfel încât fișierele de jurnal să nu consume spațiu pe disc într-un mod necontrolat.
Un alt scenariu apare când nu știi exact cât timp ar trebui să ruleze un proces, dar vrei să te asiguri că nu va funcționa la nesfârșit. S-ar putea să ai tendința de a lăsa procese active, minimizând fereastra terminalului și uitând de ele.
Unele programe, inclusiv utilitare simple, pot genera trafic de rețea care poate afecta performanța. Sau pot consuma resursele dispozitivului țintă, încetinindu-l. (Mă uit la tine, `ping`!). A lăsa aceste programe să ruleze neîntrerupt în timp ce nu ești la calculator nu este o idee bună.
Comanda `timeout` face parte din pachetul GNU Core Utils, ceea ce înseamnă că sistemele de operare Linux și Unix, inclusiv macOS, o au inclusă implicit. Nu trebuie să instalezi nimic suplimentar, poți începe să o folosești imediat.
Primii pași cu timeout
Să vedem un exemplu simplu. Comanda `ping`, folosind opțiunile implicite, rulează continuu până când o oprești cu Ctrl+C. Dacă nu o întrerupi, va continua la nesfârșit.
ping 192.168.4.28
Utilizând `timeout`, ne asigurăm că `ping` nu va funcționa la infinit, consumând lățimea de bandă a rețelei și supărând dispozitivul căruia îi facem `ping`.
Această comandă folosește `timeout` pentru a limita durata `ping`-ului la 15 secunde.
timeout 15 ping 192.168.4.28

După 15 secunde, `timeout` încheie sesiunea `ping` și ne întoarce la promptul liniei de comandă.

Utilizarea timeout cu alte unități de timp
Observă că nu am adăugat un „s” după 15. Implicit, `timeout` consideră că valoarea este în secunde. Poți adăuga „s”, dar nu va face nicio diferență.
Pentru a specifica o valoare de timp în minute, ore sau zile, adaugă „m”, „h” sau „d”, respectiv.
Pentru a rula `ping` timp de trei minute, folosim această comandă:
timeout 3m ping 192.168.4.28

`ping` va rula timp de trei minute, după care `timeout` va interveni și va opri sesiunea.

Limitarea capturii de date cu timeout
Unele fișiere de captură de date pot crește rapid. Pentru a evita ca aceste fișiere să devină prea mari, limitează durata de timp în care programul de captură este lăsat să ruleze.
În exemplul următor, folosim `tcpdump`, un instrument pentru capturarea traficului de rețea. Pe sistemele de test pe care am verificat acest articol, `tcpdump` era deja instalat pe Ubuntu Linux și Fedora Linux. Pentru Manjaro Linux și Arch Linux, a fost necesară instalarea, cu ajutorul următoarei comenzi:
sudo pacman -Syu tcpdump

Putem rula `tcpdump` timp de 10 secunde cu opțiunile sale implicite și redirecționăm rezultatul către un fișier numit `capture.txt` folosind următoarea comandă:
timeout 10 sudo tcpdump > capture.txt

(`tcpdump` are propriile opțiuni pentru a salva traficul capturat într-un fișier, dar aceasta e o soluție rapidă, deoarece ne concentrăm pe `timeout`, nu pe `tcpdump`.)
`tcpdump` începe să capteze traficul și așteptăm 10 secunde. Însă, după 10 secunde, `tcpdump` continuă să ruleze și `capture.txt` continuă să crească. Va fi nevoie de un Ctrl+C rapid pentru a opri `tcpdump`.
Verificând dimensiunea `capture.txt` cu `ls`, observăm că a crescut la 209K în câteva secunde. Fișierul creștea foarte rapid!
ls -lh capture.txt
Ce s-a întâmplat? De ce `timeout` nu a oprit `tcpdump`?
Totul ține de semnale.
Trimiterea semnalului corect
Când `timeout` dorește să oprească un program, trimite semnalul SIGTERM. Acesta solicită programului să se încheie. Unele programe pot alege să ignore semnalul SIGTERM. Când se întâmplă acest lucru, trebuie să îi cerem lui `timeout` să fie mai hotărât.
Putem face acest lucru solicitând lui `timeout` să trimită semnalul SIGKILL.
Semnalul SIGKILL nu poate fi „capturat, blocat sau ignorat” – acesta trece întotdeauna. SIGKILL nu roagă politicos programul să se oprească, ci îl încheie brusc.
Putem utiliza opțiunea `-s` (semnal) pentru a-i spune lui `timeout` să trimită semnalul SIGKILL.
timeout -s SIGKILL 10 sudo tcpdump > capture.txt

De data aceasta, imediat ce au trecut 10 secunde, `tcpdump` este oprit.
Să cerem politicos mai întâi
Putem ruga `timeout` să încerce să oprească programul folosind SIGTERM și să trimită SIGKILL doar dacă SIGTERM nu a funcționat.
Pentru a face acest lucru, folosim opțiunea `-k` (ucide după). Această opțiune necesită o valoare de timp ca parametru.
În această comandă, solicităm lui `timeout` să lase `dmesg` să ruleze timp de 30 de secunde și apoi să-l încheie cu semnalul SIGTERM. Dacă `dmesg` încă rulează după 40 de secunde, înseamnă că SIGTERM a fost ignorat și `timeout` va trimite SIGKILL pentru a finaliza procesul.
`dmesg` este un utilitar care poate monitoriza mesajele bufferului inelului kernelului și să le afișeze într-o fereastră de terminal.
timeout -k 40 30 dmseg -w

`dmesg` rulează timp de 30 de secunde și se oprește la primirea semnalului SIGTERM.

Știm că `dmesg` nu a fost oprit de SIGKILL, deoarece SIGKILL lasă întotdeauna un mesaj de încheiere în fereastra terminalului: „Ucis”. Ceea ce nu s-a întâmplat în acest caz.
Preluarea codului de ieșire al programului
Programele care respectă regulile transmit o valoare înapoi shell-ului când se termină. Aceasta este cunoscută ca un cod de ieșire. De obicei, acest cod informează shell-ul (sau procesul care a lansat programul) dacă programul a întâmpinat probleme.
`timeout` generează propriul cod de ieșire, dar s-ar putea să nu ne intereseze acesta. Ne interesează codul de ieșire al procesului pe care `timeout` îl controlează.
Această comandă lasă `ping` să ruleze timp de cinci secunde și să facă ping unui calculator numit Nostromo, aflat în rețeaua de test folosită pentru acest articol.
timeout 5 ping Nostromo.local

Comanda rulează timp de cinci secunde și `timeout` o termină. Apoi putem verifica codul de ieșire folosind această comandă:
echo $?

Codul de ieșire este 124. Aceasta este valoarea utilizată de `timeout` pentru a indica faptul că programul a fost încheiat prin SIGTERM. Dacă SIGKILL încheie programul, codul de ieșire este 137.
Dacă întrerupem programul cu Ctrl+C, codul de ieșire din `timeout` este zero.
timeout 5 ping Nostromo.local
echo $?

Dacă execuția programului se termină înainte ca `timeout` să-l încheie, `timeout` poate transmite codul de ieșire din program înapoi în shell.
Pentru ca acest lucru să se întâmple, programul trebuie să se oprească singur (adică nu este încheiat de `timeout`) și trebuie să folosim opțiunea `–preserve-status`.
Dacă utilizăm opțiunea `-c` (numărătoare) cu o valoare de cinci pentru `ping`, vor fi trimise doar cinci solicitări. Dacă alocăm lui `timeout` o durată de un minut, este foarte probabil ca `ping` să se încheie singur. Apoi, putem verifica valoarea de ieșire folosind `echo`.
timeout --preserve-status 1m ping -c 5 Nostromo.local
echo $?

`ping` își finalizează cele cinci solicitări și se încheie. Codul de ieșire este zero.
Pentru a verifica dacă codul de ieșire provine de la `ping`, vom forța `ping` să genereze un alt cod de ieșire. Dacă încercăm să trimitem solicitări către o adresă IP inexistentă, `ping` va eșua cu un cod de eroare. Apoi putem utiliza `echo` pentru a confirma că codul de ieșire este diferit de zero.
timeout --preserve-status 1m ping -c 5 NotHere.local
echo $?

Comanda `ping` nu poate ajunge la dispozitivul inexistent, așa că raportează o eroare și se închide. Codul de ieșire este doi. Acesta este codul de ieșire utilizat de `ping` pentru erori generale.
Stabilirea regulilor de bază
Comanda `timeout` este ideală pentru a stabili limite pentru timpul de rulare al programelor. Dacă există riscul ca fișierele jurnal să-ți umple hard disk-ul sau dacă uiți că ai lăsat un utilitar de rețea să funcționeze, include-le în `timeout` și lasă computerul să se auto-gestioneze.