Як використовувати команду timeout в Linux

Зрозуміло, настав час відірватися від комп’ютера. За допомогою команди `timeout` можна встановити часові обмеження для процесів, визначивши максимальну тривалість їхньої роботи. Ось посібник, який пояснить, як застосовувати обмеження часу для запуску програм за допомогою цієї команди.

Для чого потрібна команда `timeout`?

Команда `timeout` дозволяє обмежити час виконання програми. Але навіщо це потрібно?

Однією з причин є ситуація, коли ви точно знаєте, скільки часу повинен працювати певний процес. Типовий приклад – це контроль часу роботи програм для ведення журналів або збору даних, щоб файли журналів не займали необмежено місце на вашому накопичувачі.

Інша ситуація виникає тоді, коли ви не впевнені, як довго має тривати процес, але не хочете, щоб він працював постійно. Можливо, у вас є звичка запускати процеси, згортати вікно термінала та забувати про них.

Деякі програми, навіть прості утиліти, можуть створювати мережевий трафік, який негативно впливає на продуктивність мережі. Або вони можуть займати ресурси цільового пристрою, сповільнюючи його роботу. (Ping, я дивлюся на тебе.) Залишати такі програми працювати протягом тривалого часу, особливо коли ви не за комп’ютером, — це погана ідея.

Команда `timeout` є частиною GNU Core Utilities, тому вона вбудована в Linux та Unix-подібні операційні системи, такі як macOS. Нічого встановлювати не потрібно, ви можете використовувати її одразу.

Початок роботи з командою `timeout`

Розглянемо простий приклад. За звичайних умов, команда `ping` працюватиме, доки ви не зупините її, натиснувши Ctrl+C. Якщо її не перервати, вона просто продовжуватиме працювати.

ping 192.168.4.28

Використовуючи `timeout`, ми можемо гарантувати, що `ping` не буде працювати постійно, забираючи пропускну здатність мережі та надокучаючи пристрою, на який надсилаються запити.

Наступна команда використовує `timeout` для обмеження часу роботи `ping`. Ми встановлюємо час виконання `ping` на 15 секунд.

timeout 15 ping 192.168.4.28

Через 15 секунд `timeout` завершить сеанс `ping`, і ми повернемося до командного рядка.

Використання `timeout` з різними одиницями часу

Зверніть увагу, що нам не потрібно було додавати “s” після 15. `timeout` за замовчуванням використовує секунди. Ви можете додати “s”, але це не має значення.

Для використання значень часу, виміряних у хвилинах, годинах або днях, додайте “m”, “h” або “d” відповідно.

Щоб `ping` працював протягом трьох хвилин, використовуйте таку команду:

timeout 3m ping 192.168.4.28

`ping` працюватиме три хвилини, перш ніж `timeout` перерве сеанс `ping`.

Обмеження захоплення даних за допомогою `timeout`

Деякі файли з даними можуть дуже швидко зростати. Щоб такі файли не ставали занадто великими або навіть проблематичними за розміром, обмежте час роботи програми для їхнього збору.

У цьому прикладі ми використовуємо `tcpdump`, інструмент для збору мережевого трафіку. На тестових машинах, які використовувалися для написання цієї статті, `tcpdump` вже був встановлений в Ubuntu Linux і Fedora Linux. На Manjaro Linux і Arch Linux його потрібно було встановити за допомогою такої команди:

sudo pacman -Syu tcpdump

Ми можемо запустити `tcpdump` на 10 секунд з його налаштуваннями за замовчуванням і перенаправити його вихід у файл під назвою `capture.txt`, використавши таку команду:

timeout 10 sudo tcpdump > capture.txt

(`tcpdump` має власні параметри для збереження захопленого мережевого трафіку у файл. Це швидке рішення, оскільки ми зараз розглядаємо `timeout`, а не `tcpdump`.)

`tcpdump` починає захоплювати мережевий трафік, і ми чекаємо 10 секунд. 10 секунд минуло, але `tcpdump` все ще працює, і `capture.txt` все ще збільшується в розмірі. Щоб зупинити `tcpdump`, потрібно швидко натиснути Ctrl+C.

Перевірка розміру файлу `capture.txt` за допомогою `ls` показує, що він збільшився до 209K за кілька секунд. Цей файл зростав дуже швидко!

ls -lh capture.txt

Що сталося? Чому `timeout` не зупинив `tcpdump`?

Вся справа у сигналах.

Надсилання правильного сигналу

Коли `timeout` хоче зупинити програму, він надсилає сигнал SIGTERM. Це ввічливе прохання до програми зупинитися. Деякі програми можуть ігнорувати сигнал SIGTERM. У такому випадку нам потрібно, щоб `timeout` діяв рішучіше.

Ми можемо зробити це, попросивши `timeout` надіслати сигнал SIGKILL замість SIGTERM.

Сигнал SIGKILL не можна “перехопити, заблокувати або ігнорувати” – він завжди виконується. SIGKILL – це не ввічливе прохання до програми зупинитися. SIGKILL – це прихована сила з таймером та кувалдою.

Ми можемо використовувати параметр `-s` (signal), щоб наказати `timeout` відправити сигнал SIGKILL.

timeout -s SIGKILL 10 sudo tcpdump > capture.txt

Цього разу, як тільки мине 10 секунд, `tcpdump` зупиниться.

Спочатку ввічливе прохання

Ми можемо налаштувати `timeout` так, щоб він спочатку намагався зупинити програму за допомогою SIGTERM, і надсилав SIGKILL лише в тому випадку, якщо SIGTERM не спрацює.

Для цього ми використовуємо опцію `-k` (kill after). Опція `-k` вимагає значення часу як параметра.

У цій команді ми просимо `timeout` дозволити `dmesg` працювати протягом 30 секунд, а потім завершити його за допомогою сигналу SIGTERM. Якщо `dmesg` все ще працює через 40 секунд, це означає, що дипломатичний SIGTERM було проігноровано, і `timeout` повинен надіслати SIGKILL, щоб примусово завершити роботу.

`dmesg` – це утиліта, яка дозволяє стежити за повідомленнями кільцевого буфера ядра та відображати їх у вікні термінала.

timeout -k 40 30 dmseg -w

`dmesg` працює протягом 30 секунд і зупиняється, коли отримує сигнал SIGTERM.

Ми знаємо, що не SIGKILL зупинив `dmesg`, оскільки SIGKILL завжди залишає однослівний некролог у вікні термінала: “Убито”. Цього разу цього не сталося.

Отримання коду виходу програми

Правильні програми передають значення назад в оболонку, коли вони завершуються. Це називається кодом виходу. Зазвичай він використовується для того, щоб повідомити оболонці – або будь-якому процесу, який запустив програму – чи виникли проблеми з програмою під час її запуску.

`timeout` надає свій власний код виходу, але це не має для нас значення. Нас, ймовірно, більше цікавить код виходу з процесу, який контролює `timeout`.

Ця команда дозволяє `ping` працювати протягом п’яти секунд. Вона надсилає запит на комп’ютер під назвою Nostromo, що знаходиться в тестовій мережі, яка використовувалася для дослідження цієї статті.

timeout 5 ping Nostromo.local

Команда виконується протягом п’яти секунд, а потім `timeout` її завершує. Далі ми можемо перевірити код виходу за допомогою цієї команди:

echo $?

Код виходу 124. Це значення, яке повертає `timeout`, коли програму було завершено за допомогою SIGTERM. Якщо програма завершується за допомогою SIGKILL, код виходу дорівнює 137.

Якщо ми перервемо програму за допомогою Ctrl+C, код виходу `timeout` буде нульовим.

timeout 5 ping Nostromo.local
echo $?

Якщо виконання програми закінчується до завершення часу очікування, `timeout` може передати код виходу з програми назад в оболонку.

Щоб це сталося, програма має зупинитися сама (тобто не бути завершеною за допомогою `timeout`), і ми повинні використовувати опцію `–preserve-status`.

Якщо ми використаємо параметр `-c` (count) зі значенням 5, `ping` надішле лише п’ять запитів. Якщо ми даємо `timeout` одну хвилину, `ping` точно завершиться сам. Потім ми можемо перевірити вихідне значення за допомогою `echo`.

timeout --preserve-status 1m ping -c 5 Nostromo.local
echo $?

`ping` завершує п’ять запитів і закривається. Код виходу дорівнює нулю.

Щоб переконатися, що код виходу надходить від `ping`, давайте примусимо `ping` згенерувати інший код виходу. Якщо ми спробуємо надіслати запити `ping` на неіснуючу IP-адресу, `ping` завершиться з помилкою. Потім ми можемо використати `echo`, щоб перевірити, що код виходу не нульовий.

timeout --preserve-status 1m ping -c 5 NotHere.local
echo $?

Зрозуміло, що команда `ping` не може досягти неіснуючого пристрою, тому повідомляє про помилку та закривається. Код виходу — два. Це код виходу, який `ping` використовує для загальних помилок.

Встановлення основних правил

Команда `timeout` дозволяє встановлювати певні обмеження для запущених програм. Якщо є ризик, що файли журналів перевантажать ваш жорсткий диск або ви можете забути, що залишили запущеним мережевий інструмент, використовуйте `timeout`, щоб комп’ютер самостійно керував процесами.