pgrep测试匹配结果。
pkill命令是procps工具包的一部分,它通过模式匹配来查找进程并发送信号。pkill不仅可以按进程名匹配,还可以按完整命令行、用户、终端等多种属性进行匹配,功能比killall更加强大和灵活。
主要特点:
pkill [选项] [信号] 模式
pkill -信号 模式
| 选项 | 说明 |
|---|---|
-f, --full |
匹配完整命令行(而不仅仅是进程名) |
-x, --exact |
精确匹配进程名 |
-n, --newest |
只匹配最新(最近启动)的进程 |
-o, --oldest |
只匹配最旧(最早启动)的进程 |
-u, --euid |
按有效用户ID匹配 |
-U, --uid |
按实际用户ID匹配 |
-G, --gid |
按组ID匹配 |
-t, --terminal |
按终端匹配(tty或pts) |
-P, --parent |
按父进程ID匹配 |
-s, --session |
按会话ID匹配 |
-v, --inverse |
反转匹配(排除匹配的进程) |
-i, --ignore-case |
忽略大小写匹配 |
-c, --count |
只显示匹配的进程数,不发送信号 |
-d, --delimiter |
指定输出分隔符(默认换行) |
-l, --list-name |
列出信号名称 |
-a, --list-full |
列出匹配进程的完整命令行 |
-q, --quiet |
安静模式,不显示错误信息 |
-signal |
指定要发送的信号(默认SIGTERM) |
| 信号 | 编号 | 说明 |
|---|---|---|
| SIGHUP | 1 | 挂起信号,重新读取配置文件 |
| SIGINT | 2 | 中断信号(Ctrl+C) |
| SIGQUIT | 3 | 退出信号 |
| SIGKILL | 9 | 强制终止信号(不可捕获) |
| SIGTERM | 15 | 终止信号(默认),允许进程清理 |
| SIGSTOP | 19 | 暂停信号(不可捕获) |
| SIGCONT | 18 | 继续执行信号 |
# 终止所有firefox进程(默认发送SIGTERM)
pkill firefox
# 强制终止所有firefox进程
pkill -9 firefox
pkill -KILL firefox
# 精确匹配进程名
pkill -x bash
# 匹配进程名中包含"python"的进程
pkill python
# 匹配完整命令行中包含"python script.py"的进程
pkill -f "python script.py"
# 匹配启动特定应用的进程
pkill -f "java.*myapp.jar"
pkill -f "node.*server.js"
# 匹配带参数的进程
pkill -f "nginx.*-c /etc/nginx/nginx.conf"
# 终止指定用户的所有进程
pkill -u username
pkill -U 1000 # 按UID终止
# 终止除root用户外的所有bash进程
pkill -u root bash
# 终止www-data用户的所有nginx进程
pkill -u www-data nginx
# 终止多个用户的进程
pkill -u user1,user2,user3
# 终止指定终端的所有进程
pkill -t tty1
pkill -t pts/0
# 终止pts/0终端的所有bash进程
pkill -t pts/0 bash
# 终止所有终端(除当前终端外)的进程
pkill -t pts/ # 注意:这很危险!
# 终止最近启动的firefox进程
pkill -n firefox
# 终止最早启动的firefox进程
pkill -o firefox
# 终止最近启动的5个python进程
for i in {1..5}; do pkill -n python; done
# 只终止最新启动的SSH连接
pkill -n -f "ssh.*user@host"
# 终止除bash外的所有进程(当前用户)
pkill -v bash
# 终止除root用户外的所有进程
pkill -v -u root
# 忽略大小写匹配
pkill -i CHROME
pkill -i -f "python.*SCRIPT"
# 匹配以"worker"开头的进程
pkill "^worker"
# 匹配包含"test"的进程
pkill ".*test.*"
# 匹配数字结尾的进程
pkill "worker_[0-9]+"
# 匹配特定模式的进程
pkill -f "(python|perl).*\.py"
# 匹配特定端口的进程
pkill -f ":8080"
pkill -f "nginx.*80"
# 重启Web服务器(优雅重启)
pkill -HUP nginx
pkill -HUP apache2
# 终止用户的所有SSH会话
pkill -u username ssh
pkill -u username sshd
# 清理僵尸进程的父进程
pkill -9 -P $(ps aux | awk '$8=="Z" {print $3}')
# 终止所有Chrome标签页进程
pkill -f chrome.*--type=renderer
# 终止特定的Docker容器进程
pkill -f "docker.*container_name"
# 终止屏幕保护程序
pkill xscreensaver
pkill -f "gnome-screensaver"
# 只显示匹配的进程数,不实际终止
pgrep firefox | wc -l
pkill -c firefox # 更简单的方式
# 列出匹配的进程详细信息
pgrep -l firefox
pkill -l firefox # 显示进程名和PID
# 显示完整命令行
pgrep -a firefox
pkill -a firefox # pkill的等价方式
# 测试匹配结果(使用pgrep)
pgrep -f "python.*script"
pgrep -u www-data
| 命令 | 主要功能 | 特点 | 示例 |
|---|---|---|---|
| pkill | 模式匹配并发送信号 | 支持正则表达式,功能最强大 | pkill -f "python.*script" |
| pgrep | 模式匹配查找PID | 只查找不终止,用于测试 | pgrep -l firefox |
| killall | 按进程名终止 | 简单直观,不支持正则表达式 | killall firefox |
| kill | 按PID终止 | 需要知道PID,最精确 | kill 1234 |
#!/bin/bash
# safe_pkill.sh - 安全使用pkill的步骤
PATTERN="$1"
SIGNAL="${2:-TERM}" # 默认信号为TERM
echo "=== 安全终止进程: 模式='$PATTERN', 信号=$SIGNAL ==="
# 1. 先用pgrep测试匹配结果
echo "1. 测试匹配结果:"
MATCH_COUNT=$(pgrep -c -f "$PATTERN")
if [ "$MATCH_COUNT" -eq 0 ]; then
echo " 未找到匹配的进程"
exit 0
fi
echo " 找到 $MATCH_COUNT 个匹配进程"
# 2. 显示匹配进程的详细信息
echo "2. 匹配进程详情:"
pgrep -a -f "$PATTERN"
# 3. 交互确认
read -p "3. 确认终止这些进程? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "操作已取消"
exit 0
fi
# 4. 先尝试优雅终止
echo "4. 发送 SIG$SIGNAL 信号..."
pkill -$SIGNAL -f "$PATTERN"
# 5. 等待并检查
sleep 2
REMAINING=$(pgrep -c -f "$PATTERN")
if [ "$REMAINING" -gt 0 ]; then
echo " 仍有 $REMAINING 个进程存活"
if [ "$SIGNAL" != "KILL" ]; then
read -p " 尝试强制终止? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo " 发送 SIGKILL..."
pkill -9 -f "$PATTERN"
fi
fi
else
echo " 所有进程已终止"
fi
#!/bin/bash
# user_session_manager.sh - 批量管理用户会话
ACTION="$1"
USERNAME="$2"
case "$ACTION" in
list)
echo "当前活跃用户会话:"
who | awk '{print $1, $2, $5}' | sort | uniq
echo -e "\n按用户统计:"
who | awk '{print $1}' | sort | uniq -c
echo -e "\n按终端统计:"
who | awk '{print $2}' | sort | uniq -c
;;
kill-user)
if [ -z "$USERNAME" ]; then
echo "请指定用户名"
exit 1
fi
echo "终止用户 $USERNAME 的所有会话:"
# 先列出会话
echo "会话列表:"
who | grep "^$USERNAME"
# 询问确认
read -p "确认终止? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 0
fi
# 终止用户的所有进程
pkill -u "$USERNAME"
# 强制终止剩余进程
sleep 2
pkill -9 -u "$USERNAME" 2>/dev/null
echo "操作完成"
;;
kill-terminal)
TERMINAL="$2"
if [ -z "$TERMINAL" ]; then
echo "请指定终端 (如 pts/0, tty1)"
exit 1
fi
echo "终止终端 $TERMINAL 的所有进程:"
pkill -t "$TERMINAL"
;;
*)
echo "用法:"
echo " $0 list # 列出所有会话"
echo " $0 kill-user username # 终止指定用户的所有会话"
echo " $0 kill-terminal terminal # 终止指定终端的所有进程"
exit 1
;;
esac
#!/bin/bash
# zombie_cleaner.sh - 监控和清理僵尸进程
MONITOR_INTERVAL=60 # 监控间隔(秒)
LOG_FILE="/var/log/zombie_cleaner.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
clean_zombies() {
# 查找僵尸进程
ZOMBIE_PIDS=$(ps aux | awk '$8=="Z" {print $2}')
if [ -z "$ZOMBIE_PIDS" ]; then
log "未发现僵尸进程"
return 0
fi
ZOMBIE_COUNT=$(echo "$ZOMBIE_PIDS" | wc -l)
log "发现 $ZOMBIE_COUNT 个僵尸进程: $ZOMBIE_PIDS"
# 获取僵尸进程的父进程
for pid in $ZOMBIE_PIDS; do
PARENT_PID=$(ps -o ppid= -p "$pid" | tr -d ' ')
PARENT_CMD=$(ps -o cmd= -p "$PARENT_PID")
log "僵尸进程 $pid (父进程: $PARENT_PID, 命令: $PARENT_CMD)"
# 尝试向父进程发送SIGCHLD信号
kill -CHLD "$PARENT_PID" 2>/dev/null
# 如果父进程是init(1)或者系统进程,不要终止
if [ "$PARENT_PID" -ne 1 ] && [[ ! "$PARENT_CMD" =~ systemd|init ]]; then
# 等待一段时间后检查
sleep 1
if ps -p "$pid" > /dev/null 2>&1; then
log " 尝试终止父进程 $PARENT_PID"
kill -TERM "$PARENT_PID" 2>/dev/null
sleep 1
if ps -p "$PARENT_PID" > /dev/null 2>&1; then
log " 强制终止父进程 $PARENT_PID"
kill -KILL "$PARENT_PID" 2>/dev/null
fi
fi
fi
done
# 再次检查
sleep 2
REMAINING_ZOMBIES=$(ps aux | awk '$8=="Z"' | wc -l)
if [ "$REMAINING_ZOMBIES" -gt 0 ]; then
log "仍有 $REMAINING_ZOMBIES 个僵尸进程"
else
log "僵尸进程已清理"
fi
}
# 主循环
log "僵尸进程清理器启动"
while true; do
clean_zombies
sleep "$MONITOR_INTERVAL"
done
#!/bin/bash
# process_monitor.sh - 进程资源监控和限制
THRESHOLD_CPU=80 # CPU使用率阈值(%)
THRESHOLD_MEM=70 # 内存使用率阈值(%)
CHECK_INTERVAL=30 # 检查间隔(秒)
LOG_FILE="/var/log/process_monitor.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
monitor_processes() {
log "开始监控进程资源使用情况..."
# 获取高CPU使用率的进程
HIGH_CPU_PIDS=$(ps -eo pid,%cpu,cmd --sort=-%cpu | awk -v threshold="$THRESHOLD_CPU" '$2 > threshold && NR>1 {print $1, $2, $3}' | head -10)
if [ -n "$HIGH_CPU_PIDS" ]; then
log "高CPU使用率进程:"
echo "$HIGH_CPU_PIDS" | while read pid cpu cmd; do
log " PID:$pid CPU:${cpu}% CMD:$cmd"
# 检查是否是关键进程
if [[ "$cmd" =~ systemd|init|sshd|dbus ]]; then
log " 关键进程,跳过"
else
# 降低进程优先级
renice +10 "$pid" 2>/dev/null
log " 已降低优先级"
# 如果CPU使用率超过90%,考虑终止
if (( $(echo "$cpu > 90" | bc -l) )); then
read -p "进程 $pid ($cmd) CPU使用率 ${cpu}%,是否终止? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
kill -TERM "$pid"
log " 已发送终止信号"
fi
fi
fi
done
fi
# 获取高内存使用率的进程
HIGH_MEM_PIDS=$(ps -eo pid,%mem,cmd --sort=-%mem | awk -v threshold="$THRESHOLD_MEM" '$2 > threshold && NR>1 {print $1, $2, $3}' | head -10)
if [ -n "$HIGH_MEM_PIDS" ]; then
log "高内存使用率进程:"
echo "$HIGH_MEM_PIDS" | while read pid mem cmd; do
log " PID:$pid MEM:${mem}% CMD:$cmd"
# 如果是Java进程,尝试触发GC
if [[ "$cmd" =~ java ]]; then
log " Java进程,尝试发送GC信号"
kill -3 "$pid" 2>/dev/null
fi
done
fi
# 检查僵尸进程
ZOMBIE_COUNT=$(ps aux | awk '$8=="Z"' | wc -l)
if [ "$ZOMBIE_COUNT" -gt 0 ]; then
log "发现 $ZOMBIE_COUNT 个僵尸进程"
fi
}
# 主循环
while true; do
monitor_processes
sleep "$CHECK_INTERVAL"
done
.会匹配任意字符,容易误匹配-f选项时要特别小心,可能匹配到不预期的进程killall命令:
killall 进程名pkill命令:
pkill 模式示例对比:
# killall只能按进程名
killall firefox
# pkill可以使用正则表达式
pkill "^firefox.*"
pkill -f "firefox.*--profile"
# killall需要-r选项才能使用正则表达式
killall -r "^firefox.*"
避免误杀的策略:
# 1. 始终先用pgrep测试
pgrep -l firefox
pgrep -a -f "python.*script"
# 2. 使用更精确的模式
# 错误:可能匹配到不相关的进程
pkill "python"
# 正确:更精确的匹配
pkill -f "python.*/home/user/script.py"
pkill -x "python3.9" # 精确匹配
# 3. 使用-f选项时要小心
# 危险:可能匹配到很多进程
pkill -f "java"
# 更安全:限定更具体的模式
pkill -f "java.*myapp.jar"
pkill -f "java -jar /opt/app/server.jar"
# 4. 结合用户过滤
pkill -u username firefox
# 5. 使用交互模式(脚本中)
read -p "确认终止? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
pkill firefox
fi
# 6. 先尝试发送TERM信号
pkill firefox
sleep 2
# 检查是否还有进程
if pgrep firefox > /dev/null; then
echo "仍有firefox进程,需要强制终止吗?"
read -p "(y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
pkill -9 firefox
fi
fi
pgrep和pkill是同一工具包(procps)中的两个命令,它们使用相同的匹配逻辑:
pgrep命令:
pkill命令:
两者关系示例:
# 1. 先用pgrep测试匹配
pgrep -l firefox
pgrep -a -f "python.*script"
# 2. 查看匹配数量
pgrep -c firefox
# 3. pkill使用相同的选项
pkill firefox
pkill -f "python.*script"
# 4. pgrep的大部分选项在pkill中也可用
pgrep -u username
pkill -u username
pgrep -t pts/0
pkill -t pts/0
# 5. 使用pgrep作为pkill的安全前置检查
PATTERN="firefox"
if pgrep -c "$PATTERN" -gt 0; then
echo "找到 $(pgrep -c "$PATTERN") 个匹配进程"
pgrep -l "$PATTERN"
# 确认后再使用pkill
fi
有几种方法可以终止特定端口的进程:
# 方法1: 使用lsof找到PID再kill
PORT=8080
PID=$(lsof -ti:$PORT)
if [ -n "$PID" ]; then
kill $PID
fi
# 方法2: 使用一行命令
lsof -ti:8080 | xargs kill
# 方法3: 使用fuser命令
fuser -k 8080/tcp
# 方法4: 使用pkill结合netstat或ss
# 查找监听8080端口的进程
netstat -tlnp | grep :8080 | awk '{print $7}' | cut -d'/' -f1 | xargs kill
# 方法5: 使用pkill -f匹配端口号
# 注意:这种方法可能不准确
pkill -f ":8080"
pkill -f ".*:8080.*"
# 方法6: 使用ss命令
ss -tlnp | grep :8080 | awk '{print $NF}' | cut -d',' -f2 | cut -d'=' -f2 | xargs kill
# 推荐的脚本
kill_port() {
local port="$1"
local signal="${2:-TERM}"
echo "查找端口 $port 的进程..."
# 使用lsof
PIDS=$(lsof -ti:"$port")
if [ -z "$PIDS" ]; then
# 尝试使用ss
PIDS=$(ss -tlnp | awk -v port=":$port" '$4 ~ port {split($6, a, "="); print a[2]}' | sort -u)
fi
if [ -z "$PIDS" ]; then
echo "未找到使用端口 $port 的进程"
return 1
fi
echo "找到进程: $PIDS"
# 显示进程信息
for pid in $PIDS; do
ps -p "$pid" -o pid,user,cmd
done
read -p "确认终止这些进程? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
for pid in $PIDS; do
kill -$signal "$pid"
echo "已发送 SIG$signal 给进程 $pid"
done
else
echo "操作取消"
fi
}
# 使用示例
kill_port 8080
kill_port 3000 KILL
pgrep测试匹配结果-u、-t等选项缩小匹配范围