pgrep 是 Linux 中用于通过进程名查找进程 ID 的命令,是 ps 命令的增强版,专门用于进程查找。
📦 基本语法
bash
pgrep [选项] 模式
🎯 主要功能
- 快速查找进程:通过进程名、用户、终端等条件查找
- 正则表达式匹配:支持正则表达式匹配进程名
- 精确匹配:可以匹配整个命令行字符串
- 父子进程关系:可以查找指定进程的子进程
- 多条件筛选:支持组合多个条件进行筛选
💡 常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
-l |
同时显示进程名 | pgrep -l ssh |
-a |
显示完整命令行 | pgrep -a ssh |
-f |
匹配完整命令行(不只是进程名) | pgrep -f "java.*jar" |
-u |
按用户筛选 | pgrep -u root |
-U |
按真实用户ID筛选 | pgrep -U 1000 |
-x |
精确匹配进程名 | pgrep -x sshd |
-n |
只显示最新的(最新的)进程 | pgrep -n bash |
-o |
只显示最旧的(最早的)进程 | pgrep -o bash |
-P |
按父进程ID查找 | pgrep -P 1234 |
-g |
按进程组ID查找 | pgrep -g 5678 |
-s |
按会话ID查找 | pgrep -s 9012 |
-t |
按终端查找 | pgrep -t pts/0 |
-d |
指定输出分隔符(默认换行) | pgrep -d, bash |
-c |
只显示匹配的进程数量 | pgrep -c nginx |
-i |
忽略大小写 | pgrep -i SSH |
-v |
反向匹配(显示不匹配的进程) | pgrep -v bash |
🔧 实际应用示例
示例 1:基本进程查找
bash
# 1. 查找 SSH 相关进程
pgrep ssh
pgrep sshd
pgrep -l ssh # 显示进程名
pgrep -a ssh # 显示完整命令行
# 2. 查找所有 bash 进程
pgrep bash
pgrep -l bash
# 3. 查找多个进程
pgrep -l "ssh\|bash\|nginx"
# 4. 统计进程数量
pgrep -c nginx
pgrep -c sshd
示例 2:按用户筛选进程
bash
# 1. 查找 root 用户的进程
pgrep -u root
pgrep -lu root
pgrep -au root
# 2. 查找特定用户的进程
pgrep -u www-data
pgrep -lu www-data
pgrep -u 1000 # 按 UID 查找
# 3. 排除特定用户的进程
pgrep -v -u root
pgrep -lv -u root
# 4. 多个用户组合
pgrep -u root,www-data,mysql
pgrep -lu root,www-data,mysql
示例 3:精确匹配和全匹配
bash
# 1. 精确匹配进程名
pgrep -x sshd # 只匹配进程名正好是 sshd
pgrep -x java # 只匹配进程名正好是 java
# 2. 匹配完整命令行
pgrep -f "nginx.*master" # 匹配命令行包含 nginx.*master
pgrep -af "java.*jar" # 匹配 Java 进程
pgrep -af "python.*script.py" # 匹配 Python 脚本
# 3. 正则表达式匹配
pgrep "^ssh" # 匹配以 ssh 开头的进程名
pgrep -f "python.*\.py$" # 匹配 Python 脚本进程
示例 4:父子进程关系
bash
# 1. 查找指定进程的子进程
pgrep -P 1234 # 查找 PID 1234 的所有子进程
pgrep -lP 1 # 查找 init 进程 (PID 1) 的子进程
# 2. 查找进程组
pgrep -g 5678
# 3. 查找会话
pgrep -s 9012
# 4. 按终端查找
pgrep -t pts/0 # 查找在 pts/0 终端运行的进程
pgrep -t tty1 # 查找在 tty1 终端运行的进程
pgrep -lt pts/0
示例 5:时间筛选
bash
# 1. 查找最新的进程
pgrep -n bash # 查找最新的 bash 进程
pgrep -ln java # 查找最新的 Java 进程
# 2. 查找最旧的进程
pgrep -o bash # 查找最旧的 bash 进程
pgrep -lo python # 查找最旧的 Python 进程
# 3. 组合使用
pgrep -n -u root # 查找 root 用户最新的进程
示例 6:输出格式控制
bash
# 1. 指定分隔符
pgrep -d, sshd # 用逗号分隔 PID
pgrep -d" " bash # 用空格分隔 PID
pgrep -d: nginx # 用冒号分隔 PID
# 2. 结合 xargs 使用
pgrep sshd | xargs ps -fp
pgrep -d" " java | xargs -n1 ps -fp
# 3. 结合 kill 使用
pgrep nginx | xargs kill
pgrep -f "python.*script.py" | xargs kill -9
⚡ 高级用法示例
示例 7:进程监控脚本
bash
#!/bin/bash
# 进程监控和管理脚本
monitor_process() {
local process_name="$1"
local max_instances="${2:-5}"
local check_interval="${3:-5}"
echo "=== 进程监控: $process_name ==="
echo "最大实例数: $max_instances"
echo "检查间隔: ${check_interval}秒"
echo ""
while true; do
local count=$(pgrep -c "$process_name")
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$timestamp] 进程 $process_name: $count 个实例"
if [ $count -gt $max_instances ]; then
echo "⚠️ 警告: 进程 $process_name 数量 ($count) 超过限制 ($max_instances)"
# 显示所有相关进程
echo "相关进程:"
pgrep -la "$process_name"
echo ""
# 终止多余的进程(保留最新的)
local pids=($(pgrep "$process_name"))
local to_kill=$((${#pids[@]} - $max_instances))
if [ $to_kill -gt 0 ]; then
echo "终止 $to_kill 个进程..."
for ((i=0; i<to_kill; i++)); do
local pid=${pids[$i]}
local proc_info=$(ps -p $pid -o command= 2>/dev/null)
echo " 终止 PID $pid: $proc_info"
kill $pid
done
fi
fi
# 检查进程状态
for pid in $(pgrep "$process_name"); do
if [ -d "/proc/$pid" ]; then
local state=$(cat "/proc/$pid/stat" 2>/dev/null | awk '{print $3}')
local cpu=$(ps -p $pid -o %cpu= 2>/dev/null)
local mem=$(ps -p $pid -o %mem= 2>/dev/null)
if [[ "$state" == "Z" ]]; then
echo "⚠️ PID $pid 是僵尸进程 (状态: $state)"
fi
if (( $(echo "${cpu:-0} > 90" | bc -l) )); then
echo "⚠️ PID $pid CPU 使用率高: ${cpu}%"
fi
if (( $(echo "${mem:-0} > 50" | bc -l) )); then
echo "⚠️ PID $pid 内存使用率高: ${mem}%"
fi
fi
done
echo ""
sleep "$check_interval"
done
}
# 使用示例
# monitor_process "python" 3 10
# monitor_process "java" 2 30
示例 8:服务健康检查
bash
#!/bin/bash
# 服务健康检查脚本
check_service() {
local service_name="$1"
local expected_instances="${2:-1}"
echo "=== 检查服务: $service_name ==="
echo "期望实例数: $expected_instances"
echo ""
# 查找进程
local pids=($(pgrep -f "$service_name"))
local count=${#pids[@]}
echo "实际实例数: $count"
if [ $count -eq 0 ]; then
echo "❌ 服务 $service_name 未运行"
return 1
elif [ $count -lt $expected_instances ]; then
echo "⚠️ 服务 $service_name 实例不足 (期望: $expected_instances, 实际: $count)"
elif [ $count -gt $expected_instances ]; then
echo "⚠️ 服务 $service_name 实例过多 (期望: $expected_instances, 实际: $count)"
else
echo "✅ 服务 $service_name 运行正常"
fi
# 显示进程详细信息
echo ""
echo "进程详细信息:"
for pid in "${pids[@]}"; do
if [ -d "/proc/$pid" ]; then
echo "PID: $pid"
echo " 命令行: $(ps -p $pid -o command=)"
echo " 用户: $(ps -p $pid -o user=)"
echo " CPU: $(ps -p $pid -o %cpu=)%"
echo " 内存: $(ps -p $pid -o %mem=)%"
echo " 运行时间: $(ps -p $pid -o etime=)"
echo " 状态: $(ps -p $pid -o stat=)"
echo ""
fi
done
return 0
}
# 批量检查服务
check_all_services() {
declare -A services=(
["sshd"]=1
["nginx"]=2
["mysqld"]=1
["postgres"]=1
["docker"]=1
["redis"]=1
)
local all_ok=true
for service in "${!services[@]}"; do
if ! check_service "$service" "${services[$service]}"; then
all_ok=false
fi
echo "========================================"
echo ""
done
if $all_ok; then
echo "✅ 所有服务检查通过"
return 0
else
echo "❌ 部分服务存在问题"
return 1
fi
}
# 定期检查
monitor_services() {
local interval="${1:-60}"
echo "=== 服务监控 ==="
echo "检查间隔: ${interval}秒"
echo "按 Ctrl+C 停止"
echo ""
while true; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始服务检查"
echo ""
if ! check_all_services; then
# 可以发送告警邮件等
echo "检测到服务异常,可能需要人工干预"
fi
echo "========================================"
echo ""
sleep "$interval"
done
}
示例 9:进程树分析
bash
#!/bin/bash
# 进程树分析工具
show_process_tree() {
local root_pid="${1:-1}"
local indent="${2:-0}"
# 获取进程信息
if [ ! -d "/proc/$root_pid" ]; then
return
fi
# 显示当前进程
local cmd=$(ps -p $root_pid -o command= 2>/dev/null | head -c 50)
local user=$(ps -p $root_pid -o user= 2>/dev/null)
local pid=$root_pid
# 缩进
for ((i=0; i<indent; i++)); do
echo -n " "
done
# 显示进程信息
echo "└─ $pid [$user] $cmd"
# 查找子进程
local children=($(pgrep -P $root_pid))
for child in "${children[@]}"; do
show_process_tree "$child" $((indent + 1))
done
}
# 按进程名查找进程树
find_process_tree() {
local process_name="$1"
echo "=== 查找进程树: $process_name ==="
echo ""
# 查找所有匹配的进程
local pids=($(pgrep "$process_name"))
if [ ${#pids[@]} -eq 0 ]; then
echo "未找到进程: $process_name"
return 1
fi
for pid in "${pids[@]}"; do
echo "进程 $pid 的进程树:"
echo ""
# 向上查找父进程直到 PID 1
local current_pid=$pid
local ancestors=()
while [ $current_pid -ne 1 ] && [ $current_pid -ne 0 ]; do
ancestors=("$current_pid" "${ancestors[@]}")
current_pid=$(ps -o ppid= -p $current_pid 2>/dev/null | tr -d ' ')
done
ancestors=("1" "${ancestors[@]}")
# 从根开始显示进程树
for ((i=0; i<${#ancestors[@]}; i++)); do
local ancestor_pid=${ancestors[$i]}
if [ $i -eq 0 ]; then
show_process_tree $ancestor_pid
else
# 只显示从该进程到目标进程的路径
echo ""
echo "从 PID 1 到 PID $pid 的路径:"
for ((j=0; j<=i; j++)); do
local p=${ancestors[$j]}
local cmd=$(ps -p $p -o command= 2>/dev/null | head -c 30)
echo -n "$p($cmd)"
[ $j -lt $i ] && echo -n " -> "
done
echo ""
fi
done
echo ""
echo "----------------------------------------"
echo ""
done
}
# 分析进程资源占用
analyze_process_resources() {
local process_name="$1"
echo "=== 进程资源分析: $process_name ==="
echo ""
# 查找所有匹配的进程
local pids=($(pgrep "$process_name"))
if [ ${#pids[@]} -eq 0 ]; then
echo "未找到进程: $process_name"
return 1
fi
echo "找到 ${#pids[@]} 个进程:"
echo ""
# 显示表头
printf "%-8s %-12s %-8s %-8s %-12s %-12s %-s\n" \
"PID" "USER" "CPU%" "MEM%" "VSZ" "RSS" "COMMAND"
printf "%s\n" "-------------------------------------------------------------------"
# 汇总统计
local total_cpu=0
local total_mem=0
local total_vsz=0
local total_rss=0
for pid in "${pids[@]}"; do
if [ -d "/proc/$pid" ]; then
local cpu=$(ps -p $pid -o %cpu= 2>/dev/null | tr -d ' ')
local mem=$(ps -p $pid -o %mem= 2>/dev/null | tr -d ' ')
local vsz=$(ps -p $pid -o vsz= 2>/dev/null | tr -d ' ')
local rss=$(ps -p $pid -o rss= 2>/dev/null | tr -d ' ')
local user=$(ps -p $pid -o user= 2>/dev/null)
local cmd=$(ps -p $pid -o command= 2>/dev/null | head -c 30)
printf "%-8s %-12s %-8s %-8s %-12s %-12s %-s\n" \
"$pid" "$user" "${cpu:-0}" "${mem:-0}" "${vsz:-0}" "${rss:-0}" "$cmd"
total_cpu=$(echo "$total_cpu + ${cpu:-0}" | bc)
total_mem=$(echo "$total_mem + ${mem:-0}" | bc)
total_vsz=$((total_vsz + ${vsz:-0}))
total_rss=$((total_rss + ${rss:-0}))
fi
done
printf "%s\n" "-------------------------------------------------------------------"
printf "%-8s %-12s %-8s %-8s %-12s %-12s\n" \
"总计" "" "$total_cpu" "$total_mem" "$total_vsz" "$total_rss"
echo ""
echo "资源使用详情:"
echo " CPU 使用率: $total_cpu%"
echo " 内存使用率: $total_mem%"
echo " 虚拟内存: $(($total_vsz / 1024)) MB"
echo " 物理内存: $(($total_rss / 1024)) MB"
# 检查是否超过阈值
local cpu_threshold=300
local mem_threshold=50
if (( $(echo "$total_cpu > $cpu_threshold" | bc -l) )); then
echo "⚠️ CPU 使用率超过 $cpu_threshold%"
fi
if (( $(echo "$total_mem > $mem_threshold" | bc -l) )); then
echo "⚠️ 内存使用率超过 $mem_threshold%"
fi
}
示例 10:进程管理工具
bash
#!/bin/bash
# 进程管理工具
# 查找并终止进程
kill_process() {
local pattern="$1"
local signal="${2:-TERM}"
echo "=== 终止进程: $pattern ==="
echo "信号: $signal"
echo ""
# 查找进程
local pids=($(pgrep -f "$pattern"))
if [ ${#pids[@]} -eq 0 ]; then
echo "未找到匹配的进程"
return 1
fi
echo "找到 ${#pids[@]} 个进程:"
for pid in "${pids[@]}"; do
local cmd=$(ps -p $pid -o command= 2>/dev/null | head -c 50)
local user=$(ps -p $pid -o user= 2>/dev/null)
echo " PID $pid [$user]: $cmd"
done
echo ""
read -p "确认终止这些进程? [y/N]: " confirm
if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
for pid in "${pids[@]}"; do
echo "终止 PID $pid..."
if kill -$signal $pid 2>/dev/null; then
echo " ✅ 已发送信号 $signal 到 PID $pid"
else
echo " ❌ 无法终止 PID $pid"
fi
done
# 等待进程终止
echo ""
echo "等待进程终止..."
local wait_time=5
for ((i=0; i<wait_time; i++)); do
local remaining=($(pgrep -f "$pattern"))
if [ ${#remaining[@]} -eq 0 ]; then
echo "所有进程已终止"
return 0
fi
echo " $(($wait_time - $i))秒后检查... 剩余 ${#remaining[@]} 个进程"
sleep 1
done
# 检查是否有进程未终止
local remaining=($(pgrep -f "$pattern"))
if [ ${#remaining[@]} -gt 0 ]; then
echo "以下进程未终止,可能需要强制终止:"
for pid in "${remaining[@]}"; do
echo " PID $pid"
done
read -p "强制终止? [y/N]: " force_confirm
if [[ "$force_confirm" == "y" || "$force_confirm" == "Y" ]]; then
for pid in "${remaining[@]}"; do
echo "强制终止 PID $pid..."
kill -9 $pid 2>/dev/null
done
fi
fi
else
echo "操作取消"
fi
}
# 重启进程
restart_process() {
local pattern="$1"
local start_command="$2"
echo "=== 重启进程: $pattern ==="
echo "启动命令: $start_command"
echo ""
# 查找进程
local pids=($(pgrep -f "$pattern"))
if [ ${#pids[@]} -gt 0 ]; then
echo "找到 ${#pids[@]} 个运行中的进程"
# 终止进程
kill_process "$pattern" "TERM"
# 等待进程完全终止
echo "等待 3 秒..."
sleep 3
else
echo "没有运行中的进程,直接启动"
fi
# 启动新进程
echo ""
echo "启动新进程..."
if eval "$start_command"; then
echo "✅ 进程启动成功"
# 等待并检查进程状态
sleep 2
local new_pids=($(pgrep -f "$pattern"))
if [ ${#new_pids[@]} -gt 0 ]; then
echo "新进程 PID: ${new_pids[@]}"
else
echo "⚠️ 进程可能启动失败"
fi
else
echo "❌ 进程启动失败"
return 1
fi
}
# 守护进程模式
daemon_process() {
local process_name="$1"
local start_command="$2"
local check_interval="${3:-10}"
echo "=== 进程守护: $process_name ==="
echo "检查间隔: ${check_interval}秒"
echo "按 Ctrl+C 停止守护"
echo ""
while true; do
local pids=($(pgrep -f "$process_name"))
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
if [ ${#pids[@]} -eq 0 ]; then
echo "[$timestamp] ❌ 进程 $process_name 未运行,正在启动..."
if eval "$start_command"; then
echo "[$timestamp] ✅ 进程启动成功"
# 等待并检查是否启动成功
sleep 2
local new_pids=($(pgrep -f "$process_name"))
if [ ${#new_pids[@]} -gt 0 ]; then
echo "[$timestamp] 新进程 PID: ${new_pids[@]}"
fi
else
echo "[$timestamp] ❌ 进程启动失败"
fi
else
echo "[$timestamp] ✅ 进程 $process_name 运行正常 (${#pids[@]} 个实例)"
# 检查进程健康状况
for pid in "${pids[@]}"; do
if [ -d "/proc/$pid" ]; then
local state=$(ps -p $pid -o stat= 2>/dev/null)
if [[ "$state" == "Z" ]]; then
echo "[$timestamp] ⚠️ PID $pid 是僵尸进程,尝试清理..."
kill -9 $pid 2>/dev/null
fi
fi
done
fi
echo ""
sleep "$check_interval"
done
}
# 进程资源限制
limit_process_resources() {
local pattern="$1"
local max_cpu="${2:-50}" # CPU 百分比
local max_mem="${3:-512}" # 内存 MB
echo "=== 进程资源限制 ==="
echo "进程模式: $pattern"
echo "CPU 限制: ${max_cpu}%"
echo "内存限制: ${max_mem}MB"
echo ""
# 查找进程
local pids=($(pgrep -f "$pattern"))
if [ ${#pids[@]} -eq 0 ]; then
echo "未找到匹配的进程"
return 1
fi
echo "找到 ${#pids[@]} 个进程:"
for pid in "${pids[@]}"; do
local cmd=$(ps -p $pid -o command= 2>/dev/null | head -c 40)
echo " PID $pid: $cmd"
# 检查是否已有限制
local cgroup=$(cat /proc/$pid/cgroup 2>/dev/null | grep -o "cpu.*\|memory.*")
if [ -n "$cgroup" ]; then
echo " ⚠️ 已存在 cgroup 限制: $cgroup"
fi
# 使用 cpulimit 限制 CPU
if command -v cpulimit &> /dev/null; then
echo " 使用 cpulimit 限制 CPU..."
cpulimit -p $pid -l $max_cpu -b
fi
# 使用 cgroups 限制内存
if [ -d "/sys/fs/cgroup/memory/limited" ]; then
echo " 使用 cgroup 限制内存..."
echo $pid > /sys/fs/cgroup/memory/limited/tasks
echo "${max_mem}M" > /sys/fs/cgroup/memory/limited/memory.limit_in_bytes
fi
echo ""
done
echo "资源限制已应用"
echo "注意: 这些限制只在进程运行时有效,重启后失效"
}
📊 常见问题解决
问题 1:pgrep 找不到进程
bash
# 1. 检查进程是否存在
ps aux | grep 进程名
# 2. 使用 -f 匹配完整命令行
pgrep -f "完整命令行"
# 3. 检查用户权限
sudo pgrep 进程名
pgrep -u root 进程名
# 4. 使用正则表达式
pgrep "^proc.*"
# 5. 检查进程名大小写
pgrep -i 进程名
问题 2:进程匹配过多
bash
# 1. 精确匹配进程名
pgrep -x 进程名
# 2. 结合 -u 限制用户
pgrep -u www-data nginx
# 3. 结合 -t 限制终端
pgrep -t pts/0 bash
# 4. 使用更精确的正则
pgrep "^nginx:"
# 5. 排除某些进程
pgrep -v -u nobody
问题 3:进程信息不完整
bash
# 1. 使用 -a 显示完整命令行
pgrep -a 进程名
# 2. 结合 ps 获取详细信息
pgrep 进程名 | xargs ps -fp
# 3. 使用 /proc 文件系统
for pid in $(pgrep 进程名); do
cat /proc/$pid/cmdline
echo
done
# 4. 使用 pstree 查看进程树
pstree -p $(pgrep 进程名)
💡 使用技巧
-
组合使用:结合其他命令进行高级操作
bash# 终止所有用户进程 pgrep -u username | xargs kill # 按 CPU 使用率排序 pgrep 进程名 | xargs ps -o pid,user,%cpu,%mem,cmd --sort=-%cpu # 监控进程变化 watch -n1 'pgrep -l 进程名' -
脚本中使用:在脚本中检查进程状态
bashif pgrep -x nginx >/dev/null; then echo "Nginx 正在运行" else echo "Nginx 未运行" fi -
定时任务:定时检查进程健康
bash# crontab 中 */5 * * * * pgrep -c nginx > 5 || systemctl restart nginx -
进程监控:实时监控特定进程
bashwhile true; do count=$(pgrep -c 进程名) echo "进程数: $count" sleep 5 done -
批量操作:对多个进程执行相同操作
bash# 备份所有进程的 cmdline for pid in $(pgrep -f "python.*script"); do cp /proc/$pid/cmdline /tmp/cmdline_$pid.txt done
pgrep 是进程管理的强大工具,特别适合在脚本中自动化和监控进程。掌握它可以让系统管理更加高效和安全。