Linux pstree 命令

pstree 命令以树状图形式显示进程之间的关系,让您可以直观地查看进程的父子关系和层次结构

语法格式

pstree [选项] [pid或用户名]

常用选项

选项 说明
-a 显示命令行参数
-c 不压缩相同的子树
-h 高亮显示当前进程及其祖先
-l 长格式显示(不截断行)
-n 按PID排序而不是按进程名排序
-p 显示进程PID
-u 显示进程的用户名
-G 使用VT100线条绘制字符
-U 使用UTF-8线条绘制字符
-A 使用ASCII字符绘制树状图
-V 显示版本信息
-H pid 高亮显示指定PID的进程

命令示例

示例1:显示进程树的基本形式

显示系统中所有进程的树状关系:

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线程
示例2:显示进程PID

使用-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)

这对于识别和操作特定进程非常有用。

示例3:显示特定用户的进程树

显示指定用户的进程树:

# 显示root用户的进程树
pstree root

# 显示www-data用户的进程树
pstree www-data

显示当前用户的进程树:

pstree $USER
示例4:显示完整命令行和用户名

使用-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显示用户名
示例5:高亮显示特定进程

高亮显示当前进程及其祖先:

pstree -h

高亮显示指定PID的进程:

pstree -H 1234

这在复杂的进程树中快速定位特定进程非常有用。

示例6:不压缩相同的子树

使用-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)

实际应用场景

场景1:分析进程依赖关系

分析复杂服务的进程结构:

#!/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
场景2:故障排查和僵尸进程检测

检测僵尸进程及其父进程:

#!/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
场景3:分析多进程应用程序

分析多进程/多线程应用程序的结构:

#!/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"

pstree输出符号说明

符号 说明 示例
普通进程连接线 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:

  • ps命令的一个选项
  • 使用ASCII字符显示层次结构
  • 可以结合ps的所有其他选项
  • 显示更详细的信息
  • 不会压缩相同的子树

示例对比:

# pstree显示
pstree -p

# ps --forest显示
ps -ef --forest

# ps auxf显示(BSD风格)
ps auxf

选择建议:

  • 需要直观的树状图:使用pstree
  • 需要详细信息结合树状图:使用ps -ef --forest
  • 需要彩色或交互式界面:使用htop(按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

最佳实践

  1. 使用合适的选项:根据需求选择合适的选项组合,如pstree -apu显示完整信息
  2. 高亮关键进程:使用-h-H选项高亮显示重要进程
  3. 结合其他命令:pstree适合查看结构,结合pstop查看详细信息
  4. 理解符号含义:熟悉pstree输出的各种符号,正确解读进程关系
  5. 处理显示问题:遇到显示问题时,尝试-A-l等选项
  6. 保存重要快照:定期保存关键服务的进程树,便于对比分析
  7. 分析进程关系:使用pstree分析复杂的多进程应用架构
  8. 故障排查:在系统故障时,使用pstree查看进程关系,定位问题
#!/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