
envocabulary v1.0.3
跟踪每个 shell 环境变量到其精确的文件和行来源。审核 shell 配置文件,查找 zsh 和 bash(在 macOS、Linux 和 FreeBSD 上)中的死项、重复项和孤立文件。
envocabulary
对于当前 shell 中的每个变量,找到设置它的文件和行——或是由哪个子系统(direnv、launchd、终端、SSH、系统)注入的。另加几个静态文件命令,用于当你的 shell 配置已经散落在 N 个文件和备份中、你已经理不清头绪的时候。
我构建这个工具是因为我每隔几个月就会浪费同样的一个小时,去追踪为什么某个 JAVA_HOME 或 PATH 指向了我没预料到的地方。which 知道命令,direnv status 知道 direnv,launchctl getenv 知道 launchd——但它们都不会告诉你 ~/.zshrc:42 才是真正的写入者。
支持 macOS、Linux 和 FreeBSD 上的 zsh 和 bash。
“啊哈”时刻
grep -r JAVA_HOME ~ 会显示所有提及该变量的文件,但从输出中看不出哪个赋值在当前 shell 中生效:
$ envocabulary explain --chain JAVA_HOME
JAVA_HOME
origin shell-file
primary ~/helpers.sh:3
chain ~/.zshrc → ~/helpers.sh
writers
~/.zshenv:8
~/helpers.sh:3 (winner)
value [hidden, use --values]
安装
一行命令(检测 OS/架构,将二进制文件放到你的 $PATH 中,并在 macOS 上清除 Gatekeeper 限制):
curl -fsSL https://raw.githubusercontent.com/sreckoskocilic/envocabulary/main/install.sh | sh
或者 go install github.com/sreckoskocilic/envocabulary/cmd/envocabulary@latest。预编译二进制文件和 Linux 软件包(.deb / .rpm / .apk / .pkg.tar.zst)位于发布页面。
命令
实时环境(内省当前运行的 shell):
scan(默认) — 打印当前环境中的所有变量,并按来源分组explain NAME— 打印所提供变量的完整归属信息path [VARNAME...]— 对冒号分隔的路径变量逐项归属;--check查找失效条目
静态文件:
inventory— 列出所有 shell 配置文件,并按类型统计定义数量catalog— 通过合并所有配置文件,打印完整的 shell 配置dedup— 跨文件重复项报告(导出、赋值、别名、函数)dangling— 列出不再引用有效目标的配置文件条目lost— 列出仅存在于孤立/备份配置文件中的定义report— 合并审计:可安全删除、需复核(值已更改的重复项)、悬空项、孤立文件;--html会在当前目录中写入一个带时间戳的.html文件clean [--full] FILE— 列出应被剥离的行;使用--full时,打印完整的清理后内容
其他:
-V,--version— 打印版本、提交和构建日期
使用 envocabulary <cmd> -h 查看标志。
下面的示例输出使用 ~/ 以示简洁;该工具除 report 外均打印绝对路径。
另一个示例:查找损坏的引用
dangling 会列出不再引用有效目标的配置文件条目——比如 JAVA_HOME=/opt/jdk-i-uninstalled 和 source ~/dotfiles/work-old.zsh 这类遗留内容:
$ envocabulary dangling
## ~/.zshrc
~/.zshrc:14 source → ~/dotfiles/work-old.zsh (source target missing)
~/.zshrc:42 export JAVA_HOME → /opt/jdk-11 (path does not exist)
另一个示例:追踪 PATH 条目
path 显示 PATH(或 MANPATH、FPATH 等)中每个条目是在哪里引入的:
$ envocabulary path PATH
## PATH
/opt/homebrew/bin ~/.zprofile:21
/usr/local/bin ~/.zprofile:1
/usr/bin /etc/zprofile:1
/bin /etc/zprofile:1
/usr/sbin /etc/zprofile:1
/sbin /etc/zprofile:1
~/.cargo/bin ~/.zshrc:22
未匹配到任何 shell 启动项赋值的条目会显示为 inherited。
--check 会筛选出目录已不存在的条目,并追溯到需要编辑的配置文件:
$ envocabulary path --check PATH
## PATH
/opt/homebrew/Cellar/go/1.25.1/libexec/bin ~/.zshrc:17 (does not exist)
/opt/pkg/env/active/bin /etc/paths.d/10-pmk-global:1 (does not exist)
/Applications/VMware /etc/paths.d/com.vmware.fusion.public:1 (does not exist)
发现失效条目时以状态 1 退出(在脚本中很有用)。
限制
- 每行一个赋值(
export EDITOR=vim VISUAL=vim只记录EDITOR)。 dangling不会解析类 PATH 的赋值或展开(export GOPATH=$HOME/go)。path的归属基于 xtrace 差异——第一个包含某条目的赋值会声明该条目,即使它只是通过$PATH展开被携带而来,而非显式添加。- 不支持的 shell: fish、nu、csh/tcsh、PowerShell。
设计上只读
envocabulary 绝不会 unset、rm 或编辑你的 shell 配置。应急工具不应该成为让情况变得更糟的东西。如果你想清理,请复制 file:line 指针并自行编辑。clean 输出到 stdout;重定向由你自己完成。