witr:一条命令告诉你「为什么它在跑」

阅读时长:8分钟

你有没有过这种时刻:服务器上 443 端口突然被占了,你花了 15 分钟,串起了 ss -tlnp → lsof -i :443 → ps aux | grep 9876 → systemctl status → docker ps,最后终于找到了那个 kubectl port-forward 的后台残留。

然后你对着终端发呆:我就想知道是谁启动了它,需要跑 4 个命令吗?

witr 这个工具,就是为了终结这种局面而生的。

从"它是什么"到"它为什么存在"

ps、top、lsof、ss、systemctl、docker ps——这些工具都没问题,但它们只回答 what,不回答 why。

你调了 4 个工具,手动拼出因果链:systemd 启动了 pm2,pm2 启动了 node,node 打开了 5001 端口。witr 把这些拼起来,一条命令给你。

它的名字来自开发者 Pranshu Parmar 最常问自己的那句话:“Why is this running?”

这种命名方式让我想起另一个经典工具 htop——简单粗暴,但一看到就懂。

一个命令能干什么

witr 的核心输入维度有 5 个:进程名、PID、端口、文件、容器。你可以单独用,也可以混着来。

# 查一个进程的因果链
witr node

# 精确匹配(避免 substring 误杀)
witr --exact nginx

# 按端口查
witr --port 5432

# 按 PID 查
witr --pid 12345

# 查某个文件被谁持有
witr --file /var/run/docker.pid

# 查容器背后的进程
witr --container myapp

# 全部混用
witr nginx --port 443 --pid 2311 --verbose

输出长这样:

Target : node
Process : node (pid 14233)
User : pm2
Command : node index.js
Started : 2 days ago (Mon 2025-02-02 11:42:10 +05:30)
Restarts : 1
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)
Listening : 127.0.0.1:5001

一个页面,你就知道:谁启动的、什么时候启动的、重启了几次、代码在哪个目录、对应哪个 git 分支、监听什么端口。这就是 witr 的价值——把原来 4 个命令的输出,折叠成 15 行。

TUI 模式:交互式仪表盘

witr 还有一个 -i 交互模式,启动后是一个分 4 个 tab 的终端仪表盘:

  • Processes — 实时进程列表,可搜索
  • Ports — 端口占用一览
  • Containers — 容器进程映射
  • Locks — 文件锁状态

按 a 切到"所有打开文件"视图,按 / 搜索,按回车看详情。这种设计让我想到 btop 的思路:同样一个工具,CLI 模式给脚本用,TUI 模式给人用。

6 种输出模式,覆盖从人到脚本的所有场景

witr node                    # 默认:完整信息
witr --short node            # 只显示因果链,适合 grep/awk
witr --tree node             # 树形结构,带子进程
witr --json node             # JSON,喂给其他工具
witr --verbose node          # 扩展信息(环境变量、警告等)
witr --warnings node         # 只显示有问题的进程

这种设计很务实:人在终端看默认输出,脚本管道吃 JSON,监控告警吃 --warnings + exit code。witr 的退出码也很有用:

代码 含义
0 进程找到,无异常
1 有警告
2 未找到
3 权限不足
4 输入无效或模糊匹配

可以直接用在 CI 里判断"服务是否在跑"。

容器时代的新痛点

Docker 环境里这个问题更严重。容器内的 PID 和宿主机 PID 完全不同,进程名字还经常被 entrypoint.sh 包装。

# witr 直接跨运行时搜索
witr --container myapp
witr --container nginx --verbose

支持 Docker、Podman、nerdctl、K8s crictl 和 FreeBSD jails,它会跨容器运行时匹配容器名、镜像、命令和 compose project/service 标签。

而且 witr 还处理了一个边界情况:systemd socket activation。当 systemd 自己占用了一个端口,但实际服务跑在容器里时,witr 会做 port → container fallback,不会让你误以为是 systemd 在提供服务。

这种细节说明作者是真正的运维痛点患者——不是从文档出发做工具,是从自己的痛苦出发。

安装:一条命令的事

witr 是单二进制静态编译,Linux、macOS、FreeBSD、Windows 全覆盖。安装方式多到你没法抱怨"我装不了":

# 官方安装脚本(推荐)
curl -fsSL https://raw.githubusercontent.com/pranshuparmar/witr/main/install.sh | sh

# Homebrew
brew install witr

# Conda
conda install -c conda-forge witr

# Winget(Windows)
winget install PranshuParmar.witr

# NPM
npm install -g @pranshuparmar/witr

# Nix
nix run github:pranshuparmar/witr

# 直接从源码编译
go install github.com/pranshuparmar/witr/cmd/witr@latest

二进制体积很小,Go 静态编译,复制到任意目录就能跑。没有依赖,没有 runtime,没有 virtualenv。

同类工具横评

工具 语言 核心能力 短板
witr Go 因果链 + 多输入维度 + TUI 无
lsof C 文件/端口/网络打开列表 只列不分析
ss C socket 统计 无因果链
fuser C 谁占了端口/PID 输出简陋
systemctl C systemd 服务管理 只看 systemd
docker ps Go 容器列表 只看容器

其他工具都是"列数据",witr 是"讲故事"。你不需要自己拼,它帮你拼好。

谁该用 witr

  • 运维/SRE:排查线上进程异常时,省掉 4 个命令的组合拳
  • 后端开发者:本地调试时想知道"为什么 3000 端口被占了"
  • DevOps/平台工程师:容器编排场景下跨运行时做进程映射
  • 安全工程师:快速识别异常进程的来源链

如果你发现自己每周至少有一次用到 lsof + ss + ps + systemctl 的组合,witr 值得装。

最后

witr 的 README 里写了它的成功标准:一个 10 年经验的 Linux 运维,在 30 秒内搞清楚为什么一个进程在跑。

我测了一下。原来的流程大概 3-5 分钟(取决于日志的复杂度),用 witr 大概 10 秒。差距不大,但每天省 5 分钟,一年就是 30 小时——够看两季美剧了。

github.com/pranshuparmar/witr
Apache-2.0 | 17.9k ⭐ | Go

相关阅读:

© 2026 softon.top

本站已稳定运行 267 天 14 小时 · 125 篇文章

使用 Hugo 构建 主题 Stack 由 Jimmy 设计 由 softon 魔改

最近构建时间:2026-09-25 22:27:09 CST