
envocabulary v1.0.5
Отслеживайте каждую переменную окружения оболочки до её точного источника: файла и строки. Проверяйте конфигурации оболочек на наличие мёртвых записей, дубликатов и осиротевших файлов в zsh и bash на macOS, Linux и FreeBSD.
envocabulary
Для каждой переменной в вашей текущей оболочке находит файл и строку, которые её задали, или определяет, какая подсистема (direnv, launchd, терминал, SSH, система) её внедрила. Плюс несколько команд для статических файлов на тот случай, когда конфигурация вашей оболочки расползлась по N файлам и бэкапам, и вы потеряли нить.
Я создал это, потому что каждые несколько месяцев терял один и тот же час, выясняя, почему какой-нибудь JAVA_HOME или PATH указывает куда-то, где я не ожидал. which знает команды, direnv status знает direnv, launchctl getenv знает launchd. Ни одна из них не скажет вам, что ~/.zshrc:42 — это фактический источник.
Работает с zsh и bash на macOS, Linux и FreeBSD. В примерах вывода ниже используется ~/ для краткости; инструмент везде печатает абсолютные пути, кроме report.
Момент «ага»
grep -r JAVA_HOME ~ показывает все файлы, где упоминается переменная. Он не говорит, какое присваивание победило в оболочке, в которой вы сидите:
$ 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]
Переменные, заданные через eval "$(brew shellenv)", eval "$(pyenv init -)" и подобные, указывают на строку eval. У сгенерированного кода нет собственной строки; eval — это то, что вы можете открыть в редакторе.
Установка
curl -fsSL https://raw.githubusercontent.com/sreckoskocilic/envocabulary/main/install.sh | sh
Скрипт определяет ОС и архитектуру, скачивает архив релиза, проверяет его контрольную сумму sha256 и проверяет подпись cosign, если установлен cosign. Он устанавливает в /usr/local/bin, если туда есть доступ на запись, иначе в ~/.local/bin, и предупреждает, если этот каталог отсутствует в вашем $PATH. На macOS он также снимает флаг карантина Gatekeeper.
Опции: sh -s -- --version v1.0.4 для фиксации версии, --bin-dir DIR для выбора места назначения.
Или go install github.com/sreckoskocilic/envocabulary/cmd/envocabulary@latest. Учтите, что сборка через go install сообщает dev для --version; только релизные бинарники несут версию, коммит и дату сборки.
Готовые бинарники и пакеты для Linux (.deb / .rpm / .apk / .pkg.tar.zst) находятся на странице релизов.
Команды
Живое окружение (читает вашу запущенную оболочку):
scan(по умолчанию) — печатает все переменные в текущем окружении, сгруппированные по источникуexplain NAME— полная атрибуция для одной переменнойpath [VARNAME...]— атрибуция по каждой записи для переменных с путями, разделёнными двоеточием;--checkнаходит мёртвые записи
Статические файлы:
inventory— перечисляет файлы конфигурации оболочки в$HOME(канонические плюс варианты бэкапов вроде.zshrc.bak) и подсчитывает определения по типуcatalog— печатает эти файлы, объединённые в порядке, в котором их читает оболочкаdedup— отчёт о дубликатах для exports, assigns, aliases, functions, внутри и между файламиdangling— перечисляет записи конфигурации, чья цель больше не существует; завершается с кодом 1, когда что-либо находитlost— перечисляет определения, которые существуют только в осиротевших/бэкапных файлахreport— комбинированный аудит: безопасно удалить, проверить (дубликаты, чьи значения различаются, плюс все дублирующиеся функции), висячие ссылки, осиротевшие файлы;--htmlзаписывает файл.htmlс отметкой времени в текущий каталогclean [--full] FILE— перечисляет строки комментариев, которые были бы удалены; с--fullпечатает очищенное содержимое
Прочее:
-V,--version— печатает версию, коммит и дату сборки
envocabulary <cmd> -h для флагов.
Коды выхода: 0 при успехе, 1 при ошибке времени выполнения или когда dangling / path --check что-то находят, 2 при ошибке использования.
Поиск сломанных ссылок
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:6
/opt/homebrew/sbin ~/.zprofile:6
/usr/local/bin /etc/zprofile:11
/usr/bin inherited
/bin inherited
~/.cargo/bin ~/.zshrc:22
Записи, не сопоставленные ни с каким присваиванием при запуске оболочки, отображаются как inherited. Это всегда включает /usr/bin, /bin, /usr/sbin и /sbin: они — начальное значение, с которого начинает трассировщик, а не то, что добавил какой-то файл.
--check фильтрует до записей, чей каталог больше не существует, и заново определяет источник по вашим dotfiles и /etc/paths.d, так что указывает на строку для редактирования:
$ 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. - Статические команды смотрят только на канонические dotfiles в
$HOME(.zshenv,.zprofile,.zshrc,.zlogin,.zlogout,.bashrc,.bash_profile,.profile) и их варианты в стиле.bak/.old. Они не следуют за$ZDOTDIR,~/.config/zsh,/etcили файлами, которые вы подключаете черезsource. danglingпропускает значения, похожие на PATH, и всё, что содержит раскрытие (export GOPATH=$HOME/go); он не может разрешить их статически.- Атрибуция
pathоснована на diff'ах xtrace. Первое присваивание, включающее запись, присваивает её себе, даже если она была перенесена через раскрытие$PATH, а не добавлена явно. - В bash код, выполненный через
eval, сообщает строкуevalплюс смещение; в bash нет маркера для тел eval, как в zsh. - Неподдерживаемые оболочки: fish, nu, csh/tcsh, PowerShell.
Только для чтения по замыслу
envocabulary никогда не выполнит unset, rm или редактирование вашей конфигурации оболочки. Аварийный инструмент не должен быть тем, что усугубляет аварию. Если вы хотите что-то почистить, скопируйте указатели file:line и сделайте правки сами. clean выводит в stdout; перенаправление делаете вы.