Як запускати фонові процеси та керувати ними в Linux

В операційній системі Linux оболонка Bash надає потужні інструменти для керування процесами, як тими, що виконуються на передньому плані, так і фоновими. Завдяки функціям керування завданнями та сигналам Bash ви можете гнучко налаштовувати спосіб виконання команд. Розглянемо детальніше, як це працює.

Основи процесів

Коли в Linux або Unix виконується будь-яка програма, створюється процес. Процес – це внутрішнє представлення запущеної програми в пам’яті комп’ютера. Кожна активна програма має свій процес. Практично все, що працює на вашому комп’ютері, є процесом, включаючи компоненти графічного оточення робочого столу, такі як GNOME або KDE, а також системні демони, що запускаються під час завантаження.

Чому не “абсолютно все”? Тому що вбудовані команди Bash, як cd, pwd, та alias, не потребують створення окремого процесу для виконання. Bash виконує ці команди безпосередньо в екземплярі оболонки, що запущена у вашому терміналі. Саме тому вони працюють так швидко – немає потреби у запуску нового процесу. (Ви можете переглянути список вбудованих команд Bash, набравши `help` у терміналі).

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

Приклад з ping

Розглянемо простий приклад: команду ping. Спробуємо пропінгувати домен wdzwdz.com, запустивши команду як процес переднього плану.

ping www.wdzwdz.com

Як бачимо, результати команди ping виводяться у терміналі. Під час виконання команди ми не можемо використовувати термінал для інших дій. Щоб зупинити команду, потрібно натиснути Ctrl+C.

Ctrl+C

Після натискання Ctrl+C команда ping виводить підсумок і завершує роботу.

Зробимо це ще раз, але цього разу замість Ctrl+C натиснемо Ctrl+Z. Завдання не буде зупинено, а стане фоновим процесом. Ми отримаємо контроль над терміналом назад.

ping www.wdzwdz.com
Ctrl+Z

На екрані з’явиться повідомлення, що процес зупинено. “Зупинено” не означає “завершено”. Це схоже на автомобіль, який зупинився на знаку “Стоп”. Він нікуди не зник, а просто чекає на подальші інструкції. Тепер цей процес працює у фоновому режимі.

Команда `jobs` показує всі завдання, що були запущені протягом поточної сесії термінала. Оскільки завдання – це процеси, ми також можемо побачити їх за допомогою команди `ps`. Використаємо обидві команди та порівняємо їхні результати. Параметр `T` покаже тільки процеси, що працюють в поточному терміналі. Зауважте, що дефіс перед `T` ставити не потрібно.

jobs
ps T

Команда `jobs` повідомляє:

  • [1]: Номер в квадратних дужках – це номер завдання. Він потрібен для керування завданням за допомогою спеціальних команд.
  • +: Плюс означає, що це завдання буде використано, якщо ми введемо команду керування завданням без номера. Це називається “завданням за замовчуванням”. Останнє додане до списку завдань завжди є “завданням за замовчуванням”.
  • Зупинено: Процес не виконується.
  • ping www.wdzwdz.com: Команда, яка запустила цей процес.

Команда `ps` повідомляє:

  • PID: Ідентифікатор процесу. Кожен процес має унікальний ідентифікатор.
  • TTY: Псевдотермінал (вікно терміналу), з якого був запущений процес.
  • STAT: Статус процесу.
  • TIME: Кількість процесорного часу, що використовує процес.
  • COMMAND: Команда, що запустила процес.

Можливі значення стовпця `STAT`:

  • D: Неперервний сон. Процес чекає на введення або виведення і не може бути перерваний.
  • I: Простій.
  • R: Виконується.
  • S: Перериваний сон.
  • T: Зупинений сигналом керування завданнями.
  • Z: Процес-зомбі. Процес завершений, але ще не “очищений” батьківським процесом.

До значення `STAT` можуть додаватися такі індикатори:

  • < : Завдання з високим пріоритетом.
  • N : Завдання з низьким пріоритетом.
  • L : Процес має сторінки, заблоковані в пам’яті, що використовуються для процесів реального часу.
  • S : Лідером сесії є оболонка, що запустила групу процесів.
  • + : Процес переднього плану.

Бачимо, що Bash має статус `Ss`. Велика літера `S` означає, що оболонка Bash спить, але її можна перервати. Мала `s` повідомляє, що оболонка є лідером сеансу. Команда `ping` має статус `T`, що означає, що вона зупинена сигналом керування завданнями. Саме це ми і зробили, натиснувши Ctrl+Z. `ps T` має статус `R`, тобто вона виконується. Знак `+` означає, що це процес переднього плану.

Команда `bg`

Команда `bg` використовується для продовження роботи фонового процесу. Її можна використовувати з номером завдання або без нього. Якщо використовувати її без номера, на передній план виводиться “завдання за замовчуванням”. Процес продовжує працювати у фоновому режимі. Ви не можете вводити дані для нього.

Якщо запустити команду `bg`, наш процес `ping` продовжить роботу:

bg

Команда `ping` знову почала виконуватися, і ми знову бачимо прокручування в терміналі. Виводиться назва команди, яку було перезапущено.

Але є проблема. Завдання виконується у фоновому режимі і не приймає введення. Як його зупинити? Ctrl+C не спрацьовує. Ми бачимо, що ми вводимо, але фоновий процес не отримує натискань клавіш і продовжує працювати.

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

Щоб зупинити фонове завдання, нам треба вивести його на передній план і тоді вже зупинити.

Команда `fg`

Команда `fg` виводить фонове завдання на передній план. Як і `bg`, її можна використовувати з номером завдання або без нього. З номером завдання вона працюватиме з конкретним завданням, а без номера – з останнім фоновим завданням.

Якщо ми введемо `fg`, наша команда `ping` вийде на передній план. Символи, які ми вводимо, змішуються з виведенням `ping`, але оболонка обробляє їх так, ніби вони були введені в командному рядку. І фактично, з точки зору Bash, так і є.

fg

Тепер, коли команда `ping` знову на передньому плані, ми можемо використовувати Ctrl+C, щоб її зупинити.

Ctrl+C

Сигнали процесів

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

Але, попри недоліки, наш приклад продемонстрував:

  • Переведення процесу у фоновий режим.
  • Продовження виконання фонового процесу.
  • Повернення процесу на передній план.
  • Зупинення процесу.

Коли ви використовуєте Ctrl+C і Ctrl+Z, ви надсилаєте сигнали процесу. Це скорочений спосіб використання команди `kill`. Всього існує 64 різних сигнали. Скористайтесь командою `kill -l` в терміналі, щоб переглянути список. Команда `kill` не є єдиним джерелом сигналів. Деякі з них генеруються автоматично іншими процесами в системі.

Деякі часто використовувані сигнали:

  • SIGHUP: Сигнал 1. Автоматично надсилається процесу, коли закривається термінал, в якому він працює.
  • SIGINT: Сигнал 2. Надсилається процесу, коли ви натискаєте Ctrl+C. Процес переривається і повинен завершитись.
  • SIGQUIT: Сигнал 3. Надсилається процесу, якщо користувач насилає сигнал виходу Ctrl+D.
  • SIGKILL: Сигнал 9. Процес негайно зупиняється, і не намагається коректно закритись.
  • SIGTERM: Сигнал 15. Сигнал за замовчуванням, який посилає команда `kill`. Це стандартний сигнал завершення програми.
  • SIGTSTP: Сигнал 20. Надсилається процесу, коли ви використовуєте Ctrl+Z. Він зупиняє процес і переводить його у фоновий режим.

Команда `kill` використовується для відправлення сигналів, для яких немає комбінацій клавіш.

Додаткове керування завданнями

Процес, переміщений у фоновий режим за допомогою Ctrl+Z, переходить у стан зупинки. Щоб відновити його роботу, потрібно скористатися командою `bg`. Запустити програму як фоновий процес відразу дуже просто. Додайте `&` наприкінці командного рядка.

Хоча фонові процеси не повинні виводити текст в термінал, ми будемо використовувати приклади, які це роблять, щоб мати щось для скріншотів. Наступна команда запустить нескінченний цикл як фоновий процес:

while true; do echo "How-To Geek Loop Process"; sleep 3; done &

Нам показано номер завдання і ідентифікатор процесу. Номер нашого завдання – 1, ідентифікатор процесу – 1979. Ці ідентифікатори використовуються для керування процесом.

Результати нескінченного циклу починають виводитись у термінал. Як і раніше, можна використовувати командний рядок, але всі команди, які ми вводимо, змішуються з виводом процесу.

ls

Щоб зупинити процес, можна використати `jobs` для перевірки номера завдання, а потім скористатись `kill`.

Команда `jobs` каже, що наш процес – завдання номер 1. Щоб використати цей номер у команді `kill`, перед ним потрібно поставити знак відсотка `%`.

jobs
kill %1

Команда `kill` посилає сигнал `SIGTERM` (сигнал номер 15), і процес завершується. Після натискання Enter буде показано статус завдання. Він повідомляє, що процес “завершено”. Якщо процес не відповідає на команду `kill`, можна надіслати сигнал вищого пріоритету – `SIGKILL` (сигнал номер 9). Просто поставте цифру 9 між командою `kill` і номером завдання.

kill 9 %1

Підсумки

Отже, що ми навчилися:

  • Ctrl+C: надсилає `SIGINT` (сигнал 2) процесу і повідомляє йому про завершення (якщо він приймає введення).
  • Ctrl+D: надсилає `SIGQUIT` (сигнал 3) процесу і повідомляє йому про завершення (якщо він приймає введення).
  • Ctrl+Z: надсилає `SIGTSTP` (сигнал 20) процесу і наказує йому зупинитися (призупинити) та стати фоновим процесом.
  • jobs: показує фонові завдання та їх номери.
  • bg job_number: відновлює роботу фонового процесу. Якщо номер не вказано, використовується останній переведений у фоновий режим процес.
  • fg job_number: виводить фоновий процес на передній план і відновлює його. Якщо номер не вказано, використовується останній переведений у фоновий режим процес.
  • команда &: додавання амперсанду `&` в кінці командного рядка виконує команду як фоновий процес.
  • kill %job_number: надсилає `SIGTERM` (сигнал 15) процесу, щоб завершити його.
  • kill 9 %job_number: надсилає `SIGKILL` (сигнал 9) процесу та примусово його зупиняє.