Полное название этого вопроса:
Bash: Что делать, если сочетание клавиш control-c не завершает процесс из-за того, что скрипт bash содержит цикл, который вызывает другой процесс: Есть ли лучшее решение для кнопки включения/выключения питания?
Название этого вопроса говорит само за себя, но вот более подробная информация:
У меня запущен bash-скрипт, который вызывает другую программу. (Запускает / выполняет другую программу.)
Эта программа представляет собой программу подгонки данных/кривых, которую нельзя прервать с помощью CTRL-C
. Но, прочитав это,почта, я обнаружил, что могу убить его с помощьюCTRL-\
Гипотетические мысли...
Так что можно просто нажимать на клавиатуру, удерживая клавишу CTRL и нажимая клавишу \
,НОчто делать, если вы вчера купили очень дорогую механическую клавиатуру и у вас нет денег на покупку еще одной дешевой клавиатуры, которую вы готовы «раздавить» (потому что вы не хотите использовать ни одного из тех 10^6 нажатий клавиш, которые у вас есть, прежде чем ваша блестящая новая механическая клавиатура износится), или у вас нет времени найти старую клавиатуру дома, потому что ваш дом либоочень сильнобеспорядок (беспорядок) или из-за чрезвычайной ситуации, например, возгорания сковороды с жареной картошкой, произошедшей одновременно...
Также учтите, что цикл вызывает эту программу подгонки, и, возможно, вы подгоняете 1000 файлов данных, нажатие клавиши \
1000 раз, скорее всего, займет много времени.
Гиперпространственные мысли...
Или даже: что, если вы допустили ошибку в скрипте bash, и он фактически выполняет бесконечный цикл?
Что можно сделать, чтобы остановить выполнение родительского скрипта в этой ситуации? Вы можете отключить компьютер от сети, удерживать кнопку питания в течение 10 секунд, чтобы выключить его, или бросить его в огонь, чтобы остановить его работу, но эти решения кажутся неразумными из-за возможной потери данных, которая может произойти.
Теоретически можно запустить системный монитор и, возможно, завершить процесс bash, но это может быть трудно найти, если у вас много таких процессов с одинаковым именем... Кроме того, у вас может быть одноядерный компьютер или многоядерный компьютер с, скажем, N ядрами, на котором запущено N процессов, которые все пытаются использовать 100 % ЦП. Или, возможно, только 1 процесс использует больше, чем 4 ГБ оперативной памяти, и поэтому ваш компьютер работает очень медленно по этой причине... Слишком медленно, по крайней мере, для запуска системного монитора на данный момент. Следующий лучший вариант после этого — нажать CTRL-ALT-F1 и попытаться войти в систему как root и найти проблемный родительский процесс bash, используя ps -A
... kill PID
Но опять же, это может занять много минут вашего времени, если ваш компьютер настолько загружен, что он постоянно пишет в файл подкачки.
SIG TERM exec cpu_broken.sh; возобновить работу; очистить экран; очистить thought_processes; продолжить...
Есть ли лучшее решение?
решение1
Итак, по сути, вы запускаете скрипт, который делает все недоступным, и вы хотите быстрое и простое решение, чтобы остановить его. Альтернативой выключению питания является удержание SYSRQклавиши (во многих случаях это то же самое, что и PRTSCклавиша), и нажатие по одной клавише R, E, I, S, U, B. По сути, это безопасный способ завершить все запущенные процессы и перезапустить систему.
Альтернатива этому - sudo nano /proc/sysrq-trigger
написать b в этом файле и сохранить. Система немедленно перезагрузится
Больше информации: https://en.wikipedia.org/wiki/Magic_SysRq_key
решение2
Вам нужно убить всю группу процессов. Идентификатор группы процессов (PGID) — это PID процесса, который запустил группу. Чтобы убить группу процессов, вам нужно найти PID процесса, который запустил группу процессов, т.е. скрипт или команду, которая все это запустила. Синтаксис:
kill -- -PGID
Например:
kill -- -1234
Здесь 1234 — это PGID (идентификатор группы процессов).
Это отправит SIGTERM всем процессам в группе процессов. Чтобы отправить другой сигнал, например SIGKILL (9), выполните:
kill -9 -1234
Как найти PGID:
Ты можешь сделать:
ps -eo 'pid,ppid,pgid,cmd'
Это покажет PID, PPID (идентификатор родительского процесса), PGID и имя процесса.
Теперь вы можете использовать grep
или любой другой подходящий метод, чтобы найти PGID, а затем уничтожить его способами, указанными выше.
Причина, по которой я создал команду для отображения PPID, заключается в том, что вы также можете попытаться завершить процесс на основе сопоставления PPID pkill
:
pkill -P PPID
Например:
pkill -P 6789
Используя этот метод, вам нужно найти все родительские (и дочерние) процессы, а затем завершить их, поэтому, по моему мнению, завершение всего дерева процессов — лучший способ, если вы хотите завершить их все.
решение3
Обычно вы можете использовать top
, htop
или что-то подобное, чтобы найти процесс и завершить его (или, если вы знаете имя или PID процесса, вы можете killall
, pkill
и т. д.). Например, используя top
, я могу выбрать скрипт, запущенный из терминала, и завершить его, нажав k+ Enter:
Если это не сработает, k+ 9+ Enterследует использовать сигнал SIGKILL. SIGKILL требует немедленного завершения процесса и не ждет, пока процесс завершит очистку ресурсов и т. д., как это делает SIGTERM. Ctrl+ Cпроцесс отправляет SIGINT только для прерывания процесса, как это делает SIGTERM.
С помощью древовидного представления (нажмите t) в htop вы также можете определить родительские процессы скрипта и завершить их, чтобы убедиться, что он не продолжает зацикливаться.
Смотрите также:
- Сигнал Unix: сигналы POSIX — Википедия
- Страницы руководства UNIX: сигнал (7)(чтобы получить установленную версию запустите
man 7 signal
)