第44集:进程控制命令

章节标题

进程控制命令

核心知识点讲解

进程控制命令概述

进程控制命令是用于向进程发送信号,从而控制进程行为的命令。这些命令可以用于终止进程、暂停进程、继续进程等操作。在Linux系统中,最常用的进程控制命令包括 killpkillkillall 等。

信号的概念

信号是一种软件中断,用于通知进程发生了某个事件。当进程接收到信号时,会根据信号类型执行相应的操作。Linux系统中定义了多种信号,每种信号都有特定的含义和默认行为。

常用信号

信号编号 信号名称 描述 默认行为
1 SIGHUP 终端挂起或控制进程终止 终止进程
2 SIGINT 中断信号(Ctrl+C) 终止进程
3 SIGQUIT 退出信号(Ctrl+\) 终止进程并生成核心转储
9 SIGKILL 强制终止信号 强制终止进程(不可捕获)
15 SIGTERM 终止信号 终止进程(默认信号)
18 SIGCONT 继续信号 继续已暂停的进程
19 SIGSTOP 停止信号 暂停进程(不可捕获)
20 SIGTSTP 终端停止信号(Ctrl+Z) 暂停进程

kill 命令

kill 命令是最基本的进程控制命令,用于向指定的进程发送信号。

基本用法

# 向进程发送默认信号(SIGTERM,编号15)
kill PID

# 向多个进程发送信号
kill PID1 PID2 PID3

# 发送指定信号(使用信号编号)
kill -信号编号 PID

# 发送指定信号(使用信号名称)
kill -信号名称 PID

# 强制终止进程(发送SIGKILL信号,编号9)
kill -9 PID

# 暂停进程(发送SIGSTOP信号,编号19)
kill -19 PID

# 继续进程(发送SIGCONT信号,编号18)
kill -18 PID

示例

# 向进程发送默认终止信号
kill 1234

# 强制终止进程
kill -9 1234

# 暂停进程
kill -STOP 1234

# 继续进程
kill -CONT 1234

pkill 命令

pkill 命令是 kill 命令的扩展,用于根据进程名称或其他属性向进程发送信号。

基本用法

# 根据进程名称发送默认信号
pkill 进程名称

# 发送指定信号
pkill -信号编号 进程名称
pkill -信号名称 进程名称

# 强制终止进程
pkill -9 进程名称

# 根据完整命令行匹配
pkill -f 命令行字符串

# 根据用户匹配
pkill -u 用户名 进程名称

# 根据终端匹配
pkill -t 终端名称 进程名称

示例

# 终止所有名为nginx的进程
pkill nginx

# 强制终止所有名为apache2的进程
pkill -9 apache2

# 根据完整命令行终止进程
pkill -f "python script.py"

# 终止用户john的所有进程
pkill -u john

killall 命令

killall 命令用于根据进程名称终止所有匹配的进程。

基本用法

# 终止所有名为进程名称的进程
killall 进程名称

# 发送指定信号
killall -信号编号 进程名称
killall -信号名称 进程名称

# 强制终止进程
killall -9 进程名称

# 交互式操作(询问是否终止)
killall -i 进程名称

# 仅终止同一终端的进程
killall -t 终端名称 进程名称

# 忽略大小写
killall -I 进程名称

示例

# 终止所有名为chrome的进程
killall chrome

# 强制终止所有名为firefox的进程
killall -9 firefox

# 交互式终止进程
killall -i ssh

# 忽略大小写终止进程
killall -I NGINX

其他进程控制命令

xkill 命令

xkill 命令用于终止X Window系统中的图形化应用程序。

# 启动xkill,然后点击要终止的窗口
xkill

# 直接指定窗口ID
xkill -id 窗口ID

skill 命令

skill 命令是一个较老的进程控制命令,功能类似于 pkill

# 根据进程名称发送信号
skill 信号名称 进程名称

# 强制终止进程
skill -9 进程名称

# 根据用户匹配
skill -u 用户名 进程名称

snice 命令

snice 命令用于修改进程的优先级。

# 降低进程优先级
snice +10 PID

# 提高进程优先级
snice -5 PID

实用案例分析

案例1:终止无响应的进程

# 1. 查找无响应的进程
ps aux | grep 进程名称

# 2. 尝试使用默认信号终止进程
kill PID

# 3. 如果进程仍然无响应,使用强制终止信号
kill -9 PID

# 4. 或者使用pkill根据进程名称终止
pkill -9 进程名称

# 5. 或者使用killall根据进程名称终止
killall -9 进程名称

案例2:管理后台进程

# 1. 启动后台进程
sleep 60 &

# 2. 查看后台进程
jobs

# 3. 暂停后台进程
kill -STOP $!

# 4. 继续后台进程
kill -CONT $!

# 5. 终止后台进程
kill $!

案例3:批量终止进程

# 1. 终止所有指定名称的进程
pkill 进程名称

# 2. 终止所有包含指定字符串的进程
pkill -f "字符串"

# 3. 终止用户的所有进程
pkill -u 用户名

# 4. 终止特定终端的所有进程
pkill -t pts/0

# 5. 终止除当前shell外的所有进程
pkill -u $USER -o -x bash

案例4:安全终止服务进程

# 1. 对于系统服务,推荐使用systemctl命令
sudo systemctl stop 服务名称

# 2. 如果服务没有systemd单元文件,使用kill命令
# 先尝试SIGHUP信号(可能会重新加载配置)
kill -HUP $(cat /var/run/服务.pid)

# 然后尝试SIGTERM信号
kill -TERM $(cat /var/run/服务.pid)

# 最后如果进程仍然运行,使用SIGKILL信号
kill -KILL $(cat /var/run/服务.pid)

案例5:处理僵尸进程

# 1. 查找僵尸进程
ps aux | grep Z

# 2. 僵尸进程的PID和父进程PPID
# 僵尸进程的父进程ID是PPID列

# 3. 终止僵尸进程的父进程(注意:这可能会影响其他进程)
kill -TERM PPID

# 4. 如果父进程仍然不回收僵尸进程,强制终止父进程
kill -KILL PPID

# 5. 父进程终止后,僵尸进程会被init进程回收

代码示例

示例1:进程控制脚本

#!/bin/bash

# 进程控制脚本

# 显示帮助信息
show_help() {
    echo "进程控制脚本"
    echo "用法: $0 [选项] [进程ID或名称]"
    echo "选项:"
    echo "  -s, --signal <signal>    发送指定信号(例如:TERM, KILL, STOP, CONT)"
    echo "  -p, --pid <pid>          指定进程ID"
    echo "  -n, --name <name>        指定进程名称"
    echo "  -l, --list               列出所有可用信号"
    echo "  -h, --help               显示帮助信息"
}

# 列出所有可用信号
list_signals() {
    echo "可用信号列表:"
    kill -l
}

# 解析命令行参数
SIGNAL="TERM"
PID=""
NAME=""

while [[ $# -gt 0 ]]; do
    case $1 in
        -s|--signal)
            SIGNAL="$2"
            shift 2
            ;;
        -p|--pid)
            PID="$2"
            shift 2
            ;;
        -n|--name)
            NAME="$2"
            shift 2
            ;;
        -l|--list)
            list_signals
            exit 0
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            # 假设是进程ID或名称
            if [[ -z "$PID" && -z "$NAME" ]]; then
                if [[ $1 =~ ^[0-9]+$ ]]; then
                    PID="$1"
                else
                    NAME="$1"
                fi
            fi
            shift
            ;;
    esac
done

# 检查参数
if [[ -z "$PID" && -z "$NAME" ]]; then
    echo "错误: 必须指定进程ID或名称"
    show_help
    exit 1
fi

# 发送信号
if [[ -n "$PID" ]]; then
    # 向指定PID发送信号
    echo "向进程 $PID 发送信号 $SIGNAL"
    kill -$SIGNAL $PID
    if [[ $? -eq 0 ]]; then
        echo "信号发送成功"
    else
        echo "信号发送失败"
        exit 1
    fi
elif [[ -n "$NAME" ]]; then
    # 向指定名称的进程发送信号
    echo "向名称为 '$NAME' 的进程发送信号 $SIGNAL"
    pkill -$SIGNAL "$NAME"
    if [[ $? -eq 0 ]]; then
        echo "信号发送成功"
    else
        echo "信号发送失败"
        exit 1
    fi
fi

示例2:进程管理工具

#!/bin/bash

# 进程管理工具

# 显示帮助信息
show_help() {
    echo "进程管理工具"
    echo "用法: $0 [命令] [选项]"
    echo "命令:"
    echo "  start      启动进程"
    echo "  stop       停止进程"
    echo "  restart    重启进程"
    echo "  status     查看进程状态"
    echo "  kill       强制终止进程"
    echo "  list       列出所有进程"
    echo "选项:"
    echo "  -n, --name <name>        进程名称"
    echo "  -p, --pid <pid>          进程ID"
    echo "  -c, --command <command>  启动命令"
    echo "  -h, --help               显示帮助信息"
}

# 启动进程
start_process() {
    local command="$1"
    if [[ -z "$command" ]]; then
        echo "错误: 必须指定启动命令"
        return 1
    fi
    
    echo "启动进程: $command"
    $command &
    local pid=$!
    echo "进程已启动,PID: $pid"
    return 0
}

# 停止进程
stop_process() {
    local pid="$1"
    local name="$2"
    
    if [[ -n "$pid" ]]; then
        echo "停止进程 $pid"
        kill $pid
        if [[ $? -eq 0 ]]; then
            echo "进程已停止"
        else
            echo "停止进程失败"
            return 1
        fi
    elif [[ -n "$name" ]]; then
        echo "停止名称为 '$name' 的进程"
        pkill "$name"
        if [[ $? -eq 0 ]]; then
            echo "进程已停止"
        else
            echo "停止进程失败"
            return 1
        fi
    else
        echo "错误: 必须指定进程ID或名称"
        return 1
    fi
    return 0
}

# 重启进程
restart_process() {
    local name="$1"
    local command="$2"
    
    if [[ -n "$name" ]]; then
        echo "重启名称为 '$name' 的进程"
        pkill "$name"
        sleep 1
        if [[ -n "$command" ]]; then
            $command &
            local pid=$!
            echo "进程已重启,PID: $pid"
        else
            echo "重启失败: 未指定启动命令"
            return 1
        fi
    else
        echo "错误: 必须指定进程名称"
        return 1
    fi
    return 0
}

# 查看进程状态
status_process() {
    local pid="$1"
    local name="$2"
    
    if [[ -n "$pid" ]]; then
        echo "查看进程 $pid 的状态"
        if ps -p $pid > /dev/null 2>&1; then
            ps -p $pid -o pid,ppid,state,command
            echo "进程正在运行"
        else
            echo "进程不存在"
            return 1
        fi
    elif [[ -n "$name" ]]; then
        echo "查看名称为 '$name' 的进程状态"
        local pids=$(pgrep "$name")
        if [[ -n "$pids" ]]; then
            ps -p $pids -o pid,ppid,state,command
            echo "进程正在运行"
        else
            echo "进程不存在"
            return 1
        fi
    else
        echo "错误: 必须指定进程ID或名称"
        return 1
    fi
    return 0
}

# 强制终止进程
kill_process() {
    local pid="$1"
    local name="$2"
    
    if [[ -n "$pid" ]]; then
        echo "强制终止进程 $pid"
        kill -9 $pid
        if [[ $? -eq 0 ]]; then
            echo "进程已强制终止"
        else
            echo "强制终止进程失败"
            return 1
        fi
    elif [[ -n "$name" ]]; then
        echo "强制终止名称为 '$name' 的进程"
        pkill -9 "$name"
        if [[ $? -eq 0 ]]; then
            echo "进程已强制终止"
        else
            echo "强制终止进程失败"
            return 1
        fi
    else
        echo "错误: 必须指定进程ID或名称"
        return 1
    fi
    return 0
}

# 列出所有进程
list_processes() {
    echo "列出所有进程:"
    ps aux
}

# 解析命令行参数
if [[ $# -eq 0 ]]; then
    show_help
    exit 1
fi

COMMAND="$1"
shift

PID=""
NAME=""
COMMAND_TO_RUN=""

while [[ $# -gt 0 ]]; do
    case $1 in
        -n|--name)
            NAME="$2"
            shift 2
            ;;
        -p|--pid)
            PID="$2"
            shift 2
            ;;
        -c|--command)
            COMMAND_TO_RUN="$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            echo "未知选项: $1"
            show_help
            exit 1
            ;;
    esac
done

# 执行命令
case "$COMMAND" in
    start)
        start_process "$COMMAND_TO_RUN"
        ;;
    stop)
        stop_process "$PID" "$NAME"
        ;;
    restart)
        restart_process "$NAME" "$COMMAND_TO_RUN"
        ;;
    status)
        status_process "$PID" "$NAME"
        ;;
    kill)
        kill_process "$PID" "$NAME"
        ;;
    list)
        list_processes
        ;;
    *)
        echo "未知命令: $COMMAND"
        show_help
        exit 1
        ;;
esac

示例3:信号处理示例

#!/bin/bash

# 信号处理示例

# 定义信号处理函数
handle_signal() {
    local signal="$1"
    echo "收到信号: $signal"
    
    case "$signal" in
        SIGINT)
            echo "处理SIGINT信号(Ctrl+C)"
            ;;
        SIGTERM)
            echo "处理SIGTERM信号"
            ;;
        SIGTSTP)
            echo "处理SIGTSTP信号(Ctrl+Z)"
            ;;
        SIGCONT)
            echo "处理SIGCONT信号"
            ;;
        *)
            echo "处理其他信号"
            ;;
    esac
}

# 设置信号处理
trap "handle_signal SIGINT" INT
trap "handle_signal SIGTERM" TERM
trap "handle_signal SIGTSTP" TSTP
trap "handle_signal SIGCONT" CONT

# 主循环
echo "启动信号处理示例"
echo "进程ID: $$"
echo "按Ctrl+C发送SIGINT信号"
echo "按Ctrl+Z发送SIGTSTP信号"
echo "运行 'kill $$' 发送SIGTERM信号"
echo "运行 'kill -CONT $$' 发送SIGCONT信号"
echo "运行 'kill -9 $$' 强制终止进程"
echo ""

i=0
while true; do
    echo "运行中... 计数: $i"
    i=$((i + 1))
    sleep 1
done

总结

本集介绍了 Linux 中常用的进程控制命令,包括:

  1. 信号的概念和常用信号类型
  2. kill 命令:向指定进程发送信号
  3. pkill 命令:根据进程名称或其他属性发送信号
  4. killall 命令:根据进程名称终止所有匹配的进程
  5. 其他进程控制命令:如 xkillskillsnice

同时,本集还介绍了这些命令的基本用法、常用选项,以及多个实用案例和代码示例,包括:

  • 终止无响应的进程
  • 管理后台进程
  • 批量终止进程
  • 安全终止服务进程
  • 处理僵尸进程
  • 进程控制脚本
  • 进程管理工具
  • 信号处理示例

通过掌握这些进程控制命令和技巧,用户可以更好地管理系统中的进程,及时终止无响应的进程,合理控制进程的行为,从而提高系统的稳定性和性能。在实际工作中,应根据具体情况选择合适的进程控制命令和信号类型,避免误操作导致系统问题。

« 上一篇 进程监控工具 下一篇 » 进程优先级管理