pstree [选项] [pid或用户名]
| 选项 | 说明 |
|---|---|
-a |
显示命令行参数 |
-c |
不压缩相同的子树 |
-h |
高亮显示当前进程及其祖先 |
-l |
长格式显示(不截断行) |
-n |
按PID排序而不是按进程名排序 |
-p |
显示进程PID |
-u |
显示进程的用户名 |
-G |
使用VT100线条绘制字符 |
-U |
使用UTF-8线条绘制字符 |
-A |
使用ASCII字符绘制树状图 |
-V |
显示版本信息 |
-H pid |
高亮显示指定PID的进程 |
显示系统中所有进程的树状关系:
pstree
输出示例:
systemd─┬─ModemManager───2*[{ModemManager}]
├─NetworkManager───2*[{NetworkManager}]
├─accounts-daemon───2*[{accounts-daemon}]
├─agetty
├─avahi-daemon───avahi-daemon
├─cron
├─dbus-daemon
├─sshd───sshd───bash───pstree
└─systemd───(sd-pam)
2*[{ModemManager}]表示有2个ModemManager线程
使用-p选项显示每个进程的PID:
pstree -p
输出示例:
systemd(1)─┬─ModemManager(899)───{ModemManager}(911)
├─NetworkManager(922)───{NetworkManager}(934)
├─sshd(1234)───sshd(2345)───bash(3456)───pstree(4567)
└─systemd(987)───(sd-pam)(988)
这对于识别和操作特定进程非常有用。
显示指定用户的进程树:
# 显示root用户的进程树
pstree root
# 显示www-data用户的进程树
pstree www-data
显示当前用户的进程树:
pstree $USER
使用-a和-u选项显示详细信息:
pstree -apu
输出示例:
systemd,1 --system --deserialize 18
├─ModemManager,899 -f
│ └─{ModemManager},899,rtkit
├─NetworkManager,922 --no-daemon
│ └─{NetworkManager},934,root
├─sshd,1234 -D
│ └─sshd,2345 -R
│ └─bash,3456,john
│ └─pstree,4567 -apu,john
└─nginx,5678,john master process /usr/sbin/nginx -g daemon off;
├─nginx,5679,www-data worker process
└─nginx,5680,www-data worker process
-a显示完整命令行,-p显示PID,-u显示用户名
高亮显示当前进程及其祖先:
pstree -h
高亮显示指定PID的进程:
pstree -H 1234
这在复杂的进程树中快速定位特定进程非常有用。
使用-c选项显示所有进程,不压缩相同的子树:
pstree -c
这会显示所有进程,即使它们是相同的。对于查看线程特别有用:
pstree -cp
输出示例:
systemd(1)─┬─ModemManager(899)───{ModemManager}(911)
├─NetworkManager(922)───{NetworkManager}(934)
├─{NetworkManager}(935)
├─{NetworkManager}(936)
└─sshd(1234)───sshd(2345)───bash(3456)───pstree(4567)
分析复杂服务的进程结构:
#!/bin/bash
# 分析特定服务的进程结构
analyze_service() {
local service_name=$1
echo "=== 分析 $service_name 服务的进程结构 ==="
echo ""
# 查找服务的所有进程
pids=$(pgrep "$service_name")
if [ -z "$pids" ]; then
echo "未找到 $service_name 服务的进程"
return 1
fi
# 显示每个PID的进程树
for pid in $pids; do
echo "进程 $pid 的树状结构:"
pstree -p $pid
echo ""
done
# 显示服务的完整进程树
echo "完整进程树:"
pstree -apu | grep -A 10 -B 10 "$service_name"
}
# 使用示例
analyze_service nginx
analyze_service mysql
检测僵尸进程及其父进程:
#!/bin/bash
# 检测僵尸进程和进程异常
check_zombie_processes() {
echo "=== 僵尸进程检测 ==="
echo ""
# 查找僵尸进程
zombie_pids=$(ps aux | awk '$8=="Z" {print $2}')
if [ -z "$zombie_pids" ]; then
echo "未发现僵尸进程"
return 0
fi
echo "发现僵尸进程:"
for pid in $zombie_pids; do
echo "僵尸进程 PID: $pid"
# 查找父进程
ppid=$(ps -o ppid= -p $pid 2>/dev/null | tr -d ' ')
if [ -n "$ppid" ]; then
echo "父进程 PID: $ppid"
echo "父进程信息:"
ps -p $ppid -o pid,user,cmd
echo ""
# 显示进程树
echo "进程树:"
pstree -p $ppid | grep -A 5 -B 5 $pid
fi
echo "---"
done
}
# 检测孤儿进程
check_orphan_processes() {
echo ""
echo "=== 孤儿进程检测 ==="
echo ""
# 查找父进程为1但不是init/systemd的进程
ps -eo pid,ppid,cmd | awk '$2==1 && $3!~/(init|systemd)/ {print $0}'
}
# 执行检测
check_zombie_processes
check_orphan_processes
分析多进程/多线程应用程序的结构:
#!/bin/bash
# 分析复杂应用程序的进程结构
analyze_application() {
local app_name=$1
local app_pid=$2
echo "=== 分析 $app_name 进程结构 ==="
echo ""
if [ -z "$app_pid" ]; then
app_pid=$(pgrep -o "$app_name")
fi
if [ -z "$app_pid" ]; then
echo "未找到 $app_name 的进程"
return 1
fi
echo "主进程 PID: $app_pid"
echo ""
# 显示详细的进程树
echo "1. 详细进程树:"
pstree -apu $app_pid
echo ""
# 显示线程信息
echo "2. 线程信息:"
pstree -cp $app_pid
echo ""
# 统计进程/线程数量
echo "3. 统计信息:"
process_count=$(pstree -p $app_pid | grep -o '([0-9]\+)' | wc -l)
echo "总进程/线程数: $process_count"
# 显示子进程详细信息
echo ""
echo "4. 子进程详细信息:"
children=$(pstree -p $app_pid | grep -o '([0-9]\+)' | tr -d '()')
for child in $children; do
if [ "$child" != "$app_pid" ]; then
echo "子进程 $child:"
ps -p $child -o pid,user,%cpu,%mem,cmd
fi
done
}
# 使用示例
analyze_application "chrome"
analyze_application "java"
| 符号 | 说明 | 示例 |
|---|---|---|
─ |
普通进程连接线 | systemd─┬─sshd |
├─ |
分支开始(有后续兄弟) | ├─sshd |
└─ |
分支结束(最后一个) | └─bash |
│ |
垂直线(连接子进程) | 用于多级缩进 |
{} |
线程(花括号内) | {ModemManager} |
*N |
相同进程的数量 | 2*[{ModemManager}] |
, |
分隔符(PID、用户名等) | sshd,1234 |
+ |
进程组(某些版本) | bash+ |
| 命令 | 功能 | 特点 | 适用场景 |
|---|---|---|---|
pstree |
树状显示进程关系 | 直观的图形化表示,显示父子关系 | 分析进程层次结构 |
ps -ef --forest |
森林状显示进程 | 结合ps的丰富选项,显示详细信息 | 需要详细信息的进程树 |
ps auxf |
ASCII树状图 | BSD风格,显示进程树 | 快速查看进程关系 |
tree /proc |
显示/proc目录结构 | 基于文件系统的视图 | 了解/proc文件系统 |
ls /proc/*/task/ |
查看线程信息 | 查看进程的所有线程 | 分析多线程应用 |
htop |
交互式进程查看 | 树状视图,可交互操作 | 交互式进程管理 |
pstree命令:
ps --forest:
示例对比:
# pstree显示
pstree -p
# ps --forest显示
ps -ef --forest
# ps auxf显示(BSD风格)
ps auxf
选择建议:
pstreeps -ef --foresthtop(按F5切换树状视图)在pstree输出中,线程和进程的显示方式不同:
进程:显示为正常的进程名
systemd───sshd───bash
线程:显示在花括号{}中
systemd───{systemd}
├─sshd───{sshd}
└─bash───{bash}
查看线程的详细方法:
# 方法1:使用-c选项不压缩相同的子树
pstree -cp PID
# 方法2:查看/proc目录中的线程信息
ls /proc/PID/task/
# 方法3:使用ps命令查看线程
ps -T -p PID
ps -eLf | grep PID
# 方法4:使用top命令的线程模式
top -H -p PID
示例:查看Java进程的线程
# 查找Java进程
pid=$(pgrep -o java)
# 查看线程树
pstree -cp $pid | head -20
# 查看线程详细信息
ps -T -p $pid | head -10
pstree默认会压缩显示相同的子树,以提高可读性。例如:
nginx───2*[nginx]
这表示有2个nginx子进程。要查看所有进程,使用-c选项:
pstree -c
输出变为:
nginx───nginx
└─nginx
其他显示问题的解决方法:
1. 行被截断:使用-l选项显示完整行
pstree -l
2. 字符显示异常:指定字符集
# 使用ASCII字符
pstree -A
# 使用UTF-8字符(现代终端)
pstree -U
# 使用VT100字符(传统终端)
pstree -G
3. 显示不完整:结合其他命令
# 显示所有信息并分页查看
pstree -ap | less
# 保存到文件查看
pstree -apu > process_tree.txt
4. 特定进程显示:使用grep过滤
# 只显示包含nginx的进程树
pstree -ap | grep -A 10 -B 10 nginx
# 或者使用pstree本身的过滤
pstree -ap $(pgrep nginx | head -1)
虽然pstree主要用于人类可读的输出,但也可以用于脚本处理:
方法1:提取特定信息
#!/bin/bash
# 提取进程树中的PID信息
extract_pids() {
local pid=$1
# 获取进程树,提取所有PID
pstree -p $pid | grep -o '([0-9]\+)' | tr -d '()' | sort -n
}
# 使用示例
nginx_pid=$(pgrep -o nginx)
if [ -n "$nginx_pid" ]; then
echo "Nginx进程及其子进程PID:"
extract_pids $nginx_pid
fi
方法2:分析进程层次
#!/bin/bash
# 分析进程的深度和层次
analyze_process_depth() {
local pid=$1
# 获取进程树文本
tree_text=$(pstree -p $pid)
# 计算进程深度(通过缩进判断)
depth=$(echo "$tree_text" | grep -o "([0-9]\+)" | wc -l)
echo "进程 $pid 的子树包含 $depth 个进程/线程"
# 获取直接子进程数
children=$(echo "$tree_text" | grep -o "───([0-9]\+)" | wc -l)
echo "直接子进程数: $children"
}
# 使用示例
analyze_process_depth 1 # systemd/init进程
方法3:生成结构化数据(JSON)
#!/bin/bash
# 将进程树转换为JSON格式(简化版)
pstree_to_json() {
local pid=$1
echo "{"
echo " \"pid\": $pid,"
# 获取进程信息
process_info=$(ps -p $pid -o pid,user,cmd --no-headers)
pid_col=$(echo $process_info | awk '{print $1}')
user_col=$(echo $process_info | awk '{print $2}')
cmd_col=$(echo $process_info | awk '{print $3}')
echo " \"user\": \"$user_col\","
echo " \"command\": \"$cmd_col\","
# 获取子进程
children=$(pstree -p $pid | grep -o "───([0-9]\+)" | grep -o "[0-9]\+" | tr '\n' ' ')
if [ -n "$children" ]; then
echo " \"children\": ["
first=true
for child in $children; do
if [ "$first" = true ]; then
first=false
else
echo ","
fi
pstree_to_json $child | sed 's/^/ /'
done
echo ""
echo " ]"
else
echo " \"children\": []"
fi
echo "}"
}
# 使用示例(可能需要调整递归深度)
pstree_to_json 1 | head -50
pstree -apu显示完整信息-h或-H选项高亮显示重要进程ps、top查看详细信息-A、-l等选项#!/bin/bash
# pstree最佳实践示例
# 1. 监控关键服务的进程树
monitor_service_tree() {
local service=$1
local pid=$(systemctl show -p MainPID "$service" | cut -d= -f2)
if [ "$pid" -ne 0 ]; then
echo "=== $service 进程树监控 $(date) ==="
pstree -apu $pid
echo ""
else
echo "服务 $service 未运行"
fi
}
# 2. 定期快照比较
take_process_snapshot() {
local snapshot_file="/tmp/process_snapshot_$(date +%Y%m%d_%H%M%S).txt"
echo "=== 系统进程快照 $(date) ===" > $snapshot_file
echo "" >> $snapshot_file
# 显示init/systemd进程树
echo "系统进程树:" >> $snapshot_file
pstree -apu 1 >> $snapshot_file
echo "" >> $snapshot_file
# 显示关键服务进程
for service in nginx mysql redis; do
monitor_service_tree $service >> $snapshot_file 2>/dev/null
done
echo "快照保存到: $snapshot_file"
}
# 3. 进程变化检测
detect_process_changes() {
local old_file=$1
local new_file=$2
if [ ! -f "$old_file" ]; then
echo "没有旧的快照文件"
return
fi
echo "=== 进程变化检测 ==="
echo ""
# 比较进程树
diff "$old_file" "$new_file" | grep -E "^[<>]" | head -20
}
# 使用示例
take_process_snapshot