Найти и завершить процесс в одну строку с помощью bash и regex
Я часто сталкиваюсь с необходимостью 종료ить процесс во время программирования.
В настоящее время я использую следующий способ:
[~]$ ps aux | grep 'python csp_build.py'
user 5124 1.0 0.3 214588 13852 pts/4 Sl+ 11:19 0:00 python csp_build.py
user 5373 0.0 0.0 8096 960 pts/6 S+ 11:20 0:00 grep python csp_build.py
[~]$ kill 5124
Как я могу автоматически извлекать идентификатор процесса и завершать его в одной строке?
Например, чтобы сделать что-то подобное:
[~]$ ps aux | grep 'python csp_build.py' | kill <регулярное выражение, возвращающее pid>
5 ответ(ов)
В bash
, используя только основные инструменты, указанные в вашем вопросе^(1)^, вы можете сделать следующее:
kill $(ps aux | grep '[p]ython csp_build.py' | awk '{print $2}')
Пояснения к работе этой команды:
- Команда
ps
выводит список всех процессов. grep
фильтрует этот список по вашей строке поиска; использование[p]
— это трюк, который позволяет избежать захвата самого процессаgrep
.awk
извлекает второй столбец каждой строки, который соответствует PID процесса.- Конструкция
$(x)
означает выполнитьx
, затем взять его выходные данные и вставить их в командную строку. Выход из этого конвейераps
в данной конструкции — это список идентификаторов процессов, в результате чего у вас получится команда типаkill 1234 1122 7654
.
Вот пример, который демонстрирует это в действии:
pax> sleep 3600 &
[1] 2225
pax> sleep 3600 &
[2] 2226
pax> sleep 3600 &
[3] 2227
pax> sleep 3600 &
[4] 2228
pax> sleep 3600 &
[5] 2229
pax> kill $(ps aux | grep '[s]leep' | awk '{print $2}')
[5]+ Terminated sleep 3600
[1] Terminated sleep 3600
[2] Terminated sleep 3600
[3]- Terminated sleep 3600
[4]+ Terminated sleep 3600
В результате вы видите, что все процессы sleep
были завершены.
Теперь подробнее о том, как работает часть grep '[p]ython csp_build.py'
: когда вы запускаете sleep 3600 &
, а затем выполняете ps -ef | grep sleep
, вы обычно получаете два процесса, в которых есть sleep
: сам процесс sleep 3600
и процесс grep sleep
(поскольку в обеих командах содержится sleep
).
Тем не менее, использование ps -ef | grep '[s]leep'
не создаёт процесс grep
с sleep
в нём; вместо этого он создаёт процесс с командой grep '[s]leep'
, и вот в чём фокус: grep
не находит этот процесс, потому что ищет регулярное выражение "любой символ из класса символов [s]
(что фактически просто s
) с последующим leep
.
Другими словами, он ищет sleep
, но процесс grep
это grep '[s]leep'
, который не содержит текста sleep
.
Когда мне это показали (кто-то здесь на SO), я сразу начал использовать этот подход, потому что
- это на один процесс меньше, чем добавление
| grep -v grep
; и - это элегантно и хитро, что является редким сочетанием 😃
(1) Если вам не требуется ограничиваться только базовыми инструментами, существует команда pgrep
, которая находит процессы на основе определённых критериев (при условии, что она доступна на вашей системе).
Например, вы можете использовать pgrep sleep
, чтобы получить идентификаторы процессов для всех команд sleep
(по умолчанию она ищет по имени процесса). Если вы хотите сопоставить всю командную строку, как это показано в ps
, вы можете сделать что-то вроде pgrep -f 'sleep 9999'
.
Кроме того, pgrep
не показывает саму себя, если вы выполните pgrep pgrep
, поэтому хитрый фильтр, показанный выше, в этом случае не является необходимым.
Вы можете проверить, что процессы соответствуют вашим интересам, используя -a
для отображения полных имен процессов. Также вы можете ограничить область поиска вашими собственными процессами (или конкретным набором пользователей) с помощью параметров -u
или -U
. Более подробную информацию можно найти в man
-странице для pgrep
/pkill
.
Как только вы убедитесь, что команда будет отображать только интересующие вас процессы, вы можете использовать pkill
с теми же параметрами, чтобы отправить сигнал всем этим процессам.
Если у вас установлен pkill
, вы можете использовать следующую команду для завершения всех процессов, связанных с csp_build.py
:
pkill -f csp_build.py
Если вы хотите фильтровать только по имени процесса, а не по полному списку аргументов, просто уберите флаг -f
. Таким образом команда будет выглядеть так:
pkill csp_build.py
Это позволит завершить процессы, которые точно совпадают с указанным названием, игнорируя параметры и аргументы.
Однострочник:
ps aux | grep -i csp_build | awk '{print $2}' | xargs sudo kill -9
- Выводит 2-й столбец:
awk '{print $2}'
sudo
- опционально- Запускает
kill -9 5124
,kill -9 5373
и т.д. (kill -15 более аккуратный, но чуть медленнее)
Бонус:
У меня также определены 2 функции в моем .bash_profile (~/.bash_profile предназначен для osx, вам нужно посмотреть, что работает на вашей *nix машине).
- p ключевое_слово
- отображает все Процессы, содержащие ключевое слово
- использование, например:
p csp_build
,p python
и т.д.
код для bash_profile:
# ПОИСК ПРОЦЕССА
function p(){
ps aux | grep -i $1 | grep -v grep
}
- ka ключевое_слово
- Уб****ивает Автоматычески все процессы, содержащие это ключевое слово
- использование, например:
ka csp_build
,ka python
и т.д. - опциональный уровень убивания, например:
ka csp_build 15
,ka python 9
код для bash_profile:
# УБИВАЕТ ВСЕ
function ka(){
cnt=$( p $1 | wc -l) # общее количество найденных процессов
klevel=${2:-15} # уровень убивания, по умолчанию 15, если 2-й аргумент пуст
echo -e "\nПоиск '$1' -- Найдено" $cnt "Запущенных процессов .. "
p $1
echo -e '\nЗавершение' $cnt 'процессов .. '
ps aux | grep -i $1 | grep -v grep | awk '{print $2}' | xargs sudo kill -$klevel
echo -e "Готово!\n"
echo "Повторный поиск:"
p "$1"
echo -e "\n"
}
Команда killall -r regexp
используется для завершения процессов, имена которых соответствуют заданному регулярному выражению.
Флаг -r
или --regexp
интерпретирует шаблон имени процесса как расширенное регулярное выражение. Это позволяет более гибко задавать критерии для поиска процессов, которые вы хотите завершить.
Например, если вы хотите завершить все процессы, названия которых содержат "example", вы можете использовать следующую команду:
killall -r '.*example.*'
Это завершит все процессы, имена которых включают "example". Обратите внимание, что использование регулярных выражений может быть более рискованным, так как вы можете случайно завершить неверные процессы, если регулярное выражение не будет достаточно точным.
Это вернёт только идентификатор процесса (PID):
pgrep -f 'process_name'
Чтобы завершить любой процесс за одну команду, используйте:
kill -9 $(pgrep -f 'process_name')
Или, если вы знаете точное имя процесса, вы также можете использовать pidof
:
kill -9 $(pidof 'process_name')
Но если вы не знаете точное имя процесса, лучше использовать pgrep
.
Если есть несколько процессов с одинаковым именем и вы хотите завершить только первый, выполните:
kill -9 $(pgrep -f 'process_name' | head -1)
Также стоит отметить, что если вас беспокоит регистронезависимость, вы можете добавить опцию -i, как в grep
. Например:
kill -9 $(pgrep -fi chrome)
Больше информации о сигналах и pgrep
можно найти в документации: man 7 signal
, man signal
или man pgrep
.
Как перезагрузить настройки .bashrc без выхода и повторного входа в систему?
Bash инструмент для получения n-й строки из файла
Как выполнить рекурсивный поиск/замену строки с помощью awk или sed?
Проверка соответствия строки регулярному выражению в JS
Экранирование строки для использования в регулярных выражениях JavaScript [duplicate]