登录一台 Linux 服务器,ps aux 列出一堆进程,其中一个占了大量内存的 node 你完全不记得是谁拉起来的。端口 5000 在 LISTEN,但 lsof -i :5000 只给了你一个 PID,你得手动翻 systemd unit、PM2 进程树、Docker 容器列表,拼凑出这条因果链。witr 把这个手动过程自动化了——一条命令输出从 PID 1 到目标进程的完整起源链,外加容器检测、安全告警和交互式 TUI。
GitHub 上 pranshuparmar/witr 用 Go 写成,单二进制文件,20,600 星,支持 Linux、macOS、Windows 和 FreeBSD 四大平台,已进入 Debian sid、Homebrew、Conda、Winget 等十余个官方包管理器。作者 Pranshu Parmar 在 Hacker News 上的 Show HN 帖获得了 526 分。

核心概念:一切皆是进程问题
witr 的设计哲学是「一切皆是进程问题」。端口、服务、容器、文件锁,最终都映射到 PID。拿到 PID 后,witr 构建一条因果链解释这个 PID 为什么存在。
传统工具的分工是割裂的:ps 显示进程列表,top 显示资源占用,lsof 显示打开的文件和端口,systemctl status 显示服务状态,docker ps 显示容器列表。每条工具只回答「什么在运行」,用户需要自己跨工具关联输出来推断「为什么在运行」。witr 做的就是把这层推断自动化。
它回答四个问题:
- 什么在运行?
- 它怎么启动的?
- 什么在维持它运行?
- 它属于什么上下文?
因果链构建
witr 最核心的输出是「Why It Exists」段——一条从 PID 1 到目标进程的祖先链。以一个由 PM2 管理的 node 进程为例:
Why It Exists:
systemd (pid 1) → pm2 (pid 5034) → node (pid 14233)这不同于简单的 ppid 递归。witr 在每一跳上做语义识别,判断当前节点是 systemd unit、launchd 服务、SSH 会话、Docker 容器、PM2 管理器、cron 任务、交互式 shell、还是 Snap/Flatpak 沙箱,并在输出中标注。
Source 字段选出一个主要责任方,例如 systemd unit(附带 timer 调度信息)、launchd plist(附带触发器详情)、Docker compose 项目、或 SSH 远程会话(附带 IP 和终端)。
Context 段提供工作目录、Git 仓库名和分支、容器名和镜像、监听地址是公网还是内网。
查询模式
witr 支持五种查询入口,全部可混合使用:
按名称查询——默认子串模糊匹配,加 -x 走精确匹配:
witr node # 匹配所有含 "node" 的进程
witr nginx -x # 只匹配精确名为 nginx 的进程输出示例:
Target : node
Process : node (pid 14233)
User : pm2
Command : node index.js
Started : 2 days ago (Mon 2026-02-02 11:42:10 +05:30)
Why It Exists:
systemd (pid 1) → pm2 (pid 5034) → node (pid 14233)
Source : pm2
Working Dir : /opt/apps/expense-manager
Git Repo : expense-manager (main)
Sockets : 127.0.0.1:5001 (TCP | LISTENING)按端口查询——快速定位谁占用了端口,附带完整因果链:
witr --port 5000 --short
# systemd (pid 1) → PM2 v5.3.1: God (pid 1481580) → python (pid 1482060)按 PID 查询 + 树形输出——展示包含子进程的完整进程树:
witr --pid 143895 --treesystemd (pid 1)
└─ init-systemd(Ub (pid 2)
└─ SessionLeader (pid 143858)
└─ Relay(143860) (pid 143859)
└─ bash (pid 143860)
└─ sh (pid 143886)
└─ node (pid 143895)
├─ node (pid 143930)
├─ node (pid 144189)
└─ node (pid 144234)按文件查询——找出哪个进程持有文件:
witr --file /var/lib/dpkg/lock按容器查询——跨运行时搜索:
witr --container redis--container 标志会搜索 Docker、Podman、nerdctl、K8s/crictl、Incus、LXC、LXD 和 FreeBSD jails,按容器名、镜像名、启动命令或 compose 项目/服务名匹配。加 --verbose 可输出挂载、网络和 compose 元数据。
多个输入可混用,结果按输入顺序分段输出。所有输出模式(--short、--tree、--json、--env、--warnings、--verbose)都兼容多输入。
安全告警
witr 在追踪进程的同时做安全检查,遇到以下情况会在 Warnings 段标出:
- 进程以 root 身份运行
- 非 root 进程持有危险 Linux capabilities(CAP_SYS_ADMIN 等)
- 进程监听在公网接口(0.0.0.0 / ::)
- 进程重启次数超过阈值
- 内存占用超过 1GB RSS
- 运行时间超过 90 天
- 二进制文件已被删除(可能被入侵后替换)
- LD_PRELOAD / DYLD 注入指标
--warnings 模式只输出告警,适合在 CI 管道或监控脚本中使用。
交互式 TUI
不带参数运行 witr 或加 -i 标志进入交互式 TUI,提供四个标签页:
- Processes:所有运行中进程的实时列表,支持排序和过滤,右侧面板展示选中进程的祖先树
- Ports:所有监听/打开端口,按
a切换 LISTEN-only 和全部,右侧附带归属进程 - Containers:跨 Docker、Podman、nerdctl、K8s、Incus、LXC、LXD、FreeBSD jails 的统一容器列表,含名称、镜像、状态、端口、命令,点击可查看挂载和网络详情
- Locks:系统级文件锁(Linux POSIX/FLOCK,macOS/FreeBSD 从 lsof 派生),按
a切换为「所有打开文件」模式
TUI 支持鼠标操作(导航、排序、点击行),自适应明暗终端主题,进程/端口/容器/锁列表以 3 秒为基准自动刷新(高负载下自动退避)。Unix 平台上可直接在 UI 中对进程发送信号(Kill、Terminate、Pause、Resume)或调整 nice 值。
跨平台架构
witr 在每个平台上用原生 API 直采数据,不依赖外部命令拼装:
| 平台 | 数据采集方式 |
|---|---|
| Linux | /proc 文件系统直读 |
| macOS | ps、lsof、sysctl、pgrep、launchctl |
| Windows | Win32 原生 API(ToolHelp32、PSAPI、Service Control Manager),不依赖 PowerShell 或 WMI |
| FreeBSD | procstat、ps、lsof |
Windows 版本值得注意:它不经过 PowerShell 或 WMI,启动快,不会出现 Get-CimInstance 挂起问题。这对在 Windows Server 上做运维排查的团队是一个实际优势。
跨平台功能支持存在差异。环境变量查看在 macOS 受 SIP 限制,Windows 上受保护进程不可读。tmux/screen 检测不支持 Windows。调度检测(systemd timers / launchd intervals)不支持 Windows 和 FreeBSD。文件锁在 Windows 上只返回计数。完整矩阵见仓库 README 的 Feature Compatibility Matrix。
服务管理器检测
witr 在每个平台上识别不同的 init 系统:
- Linux: systemd(含 unit 文件路径、timer 调度信息、服务描述)
- macOS: launchd(含 plist 路径、触发器详情)
- Windows: Services(含注册表键、Display Name)
- FreeBSD: rc.d(含 rc 脚本路径、rc 头描述)
检测到容器运行时后,witr 能穿透容器边界追踪宿主进程和容器内进程的关系,包括 Docker compose 项目/服务映射。
SSH 会话检测支持所有四个平台,会输出远程 IP 和终端信息。tmux/screen 检测会在 Source 段显示会话名。
安装
最常用的三种方式:
# Homebrew (macOS/Linux)
brew install witr
# Debian/Ubuntu (sid/26.04+)
sudo apt install witr
# Conda (全平台)
conda install -c conda-forge witrWindows 上可通过 Winget、Chocolatey 或 Scoop 安装。npm 也可安装(npm install -g @pranshuparmar/witr),走二进制下载而非 Node.js 运行时。Go 开发者可以直接 go install github.com/pranshuparmar/witr/cmd/witr@latest。
安装脚本一键安装(Linux/macOS/FreeBSD):
curl -fsSL https://raw.githubusercontent.com/pranshuparmar/witr/main/install.sh | bash首次使用建议直接在浏览器试用,作者提供了交互式在线教程(pranshuparmar.github.io/witr),在一个模拟 Linux 环境中走完查询流程,无需安装。
退出码
witr 定义了六个退出码,方便脚本化集成:
| 码 | 含义 |
|---|---|
| 0 | 进程已找到,无告警 |
| 1 | 进程已找到,有告警 |
| 2 | 未找到匹配进程或服务 |
| 3 | 权限不足 |
| 4 | 输入无效或匹配歧义 |
| 5 | 内部错误 |
示例集成:
witr nginx --short
case $? in
0) echo "All clear" ;;
1) echo "Warnings detected" ;;
2) echo "Process not running" ;;
3) echo "Need elevated privileges" ;;
esac适用场景
witr 解决的核心痛点是运维排障中的「这个进程到底是谁拉起来的」。典型场景包括:
- 登录一台陌生服务器,快速理解进程拓扑
- 生产事故排查,几秒内定位异常进程的来源
- 安全审计,快速发现 root 运行、公网暴露、二进制替换等异常
- 容器化环境调试,跨运行时统一查看容器状态
- CI/CD 管道中自动化检测风险进程
对于经常需要在多台机器间切换的 SRE 和 DevOps 工程师,witr 把 ps + lsof + ss + systemctl + docker ps 的手动关联流程压缩到一条命令。单二进制、零运行时依赖、六大包管理器分发的设计,让它可以在任何机器上几秒部署。