
Verfolge jede Shell-Umgebungsvariable bis zu ihrem genauen Datei- und Zeilenursprung. Prüfe Shell-Konfigurationen auf tote Einträge, Duplikate und verwaiste Dateien in zsh und bash unter macOS, Linux und FreeBSD.
Finde für jede Variable in deiner aktuellen Shell die Datei und Zeile, die sie gesetzt hat, oder welches Subsystem (direnv, launchd, Terminal, SSH, System) sie injiziert hat. Dazu ein paar Befehle für statische Dateien für den Moment, in dem deine Shell-Konfiguration über N Dateien und Backups verstreut ist und du den Überblick verloren hast.
Ich habe das gebaut, weil ich alle paar Monate dieselbe Stunde damit verbracht habe, nachzuvollziehen, warum irgendein JAVA_HOME oder PATH auf etwas zeigte, das ich nicht erwartet hatte. which kennt Befehle, direnv status kennt direnv, launchctl getenv kennt launchd. Keines davon sagt dir, dass ~/.zshrc:42 der tatsächliche Verursacher ist.
Funktioniert mit zsh und bash auf macOS, Linux und FreeBSD. Die Beispielausgabe unten verwendet ~/ der Kürze wegen; das Tool gibt überall absolute Pfade aus, außer bei report.
grep -r JAVA_HOME ~ zeigt jede Datei, die die Variable erwähnt. Es sagt dir nicht, welche Zuweisung in der Shell, in der du gerade sitzt, gewonnen hat:
$ 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]
Variablen, die durch eval "$(brew shellenv)", eval "$(pyenv init -)" und ähnliches gesetzt werden, zeigen auf die eval-Zeile. Der generierte Code hat keine eigene Zeile; das eval ist das, was du in einem Editor öffnen kannst.
curl -fsSL https://raw.githubusercontent.com/sreckoskocilic/envocabulary/main/install.sh | sh
Das Skript erkennt OS und Architektur, lädt das Release-Archiv herunter, verifiziert dessen sha256-Prüfsumme und verifiziert die cosign-Signatur, wenn cosign installiert ist. Es installiert nach /usr/local/bin, wenn dieses beschreibbar ist, andernfalls nach ~/.local/bin, und warnt, wenn dieses Verzeichnis nicht in deinem $PATH liegt. Unter macOS löscht es außerdem das Gatekeeper-Quarantäne-Flag.
Optionen: sh -s -- --version v1.0.4, um eine Version festzulegen, --bin-dir DIR, um das Zielverzeichnis zu wählen.
Oder go install github.com/sreckoskocilic/envocabulary/cmd/envocabulary@latest. Beachte, dass ein go install-Build für --version dev meldet; nur Release-Binaries tragen die Version, den Commit und das Build-Datum.
Vorgefertigte Binaries und Linux-Pakete (.deb / .rpm / .apk / .pkg.tar.zst) findest du auf der Releases-Seite.
Live-Umgebung (liest deine laufende Shell):
scan (Standard) — gibt alle Variablen in der aktuellen Umgebung gruppiert nach Ursprung ausexplain NAME — vollständige Zuordnung für eine Variablepath [VARNAME...] — Zuordnung pro Eintrag für doppelpunktgetrennte Pfadvariablen; --check findet tote EinträgeStatische Dateien:
inventory — listet die Shell-Konfigurationsdateien in $HOME auf (die kanonischen plus Backup-Varianten wie .zshrc.bak) und zählt Definitionen nach Typcatalog — gibt diese Dateien aneinandergehängt in der Reihenfolge aus, in der die Shell sie liestdedup — Duplikatbericht für exports, assigns, aliases, functions, innerhalb und über Dateien hinwegdangling — listet Konfigurationseinträge auf, deren Ziel nicht mehr existiert; beendet mit 1, wenn welche gefunden werdenlost — listet Definitionen auf, die nur in verwaisten/Backup-Dateien existierenreport — kombiniertes Audit: sicher zu löschen, prüfen (Duplikate mit abweichendem Wert, plus alle doppelten Funktionen), dangling, verwaiste Dateien; --html schreibt eine zeitgestempelte .html-Datei in das aktuelle Verzeichnisclean [--full] FILE — listet Kommentarzeilen auf, die entfernt würden; mit --full wird der bereinigte Inhalt ausgegebenSonstiges:
-V, --version — gibt Version, Commit und Build-Datum ausenvocabulary <cmd> -h für Flags.
Exit-Codes: 0 bei Erfolg, 1 bei einem Laufzeitfehler oder wenn dangling / path --check etwas finden, 2 bei einem Nutzungsfehler.
dangling listet Konfigurationseinträge auf, die auf nichts mehr zeigen, die Art von Überbleibseln wie JAVA_HOME=/opt/jdk-i-uninstalled und 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 zeigt, wo jeder Eintrag in PATH (oder MANPATH, FPATH usw.) eingeführt wurde:
$ 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
Einträge, die keiner Shell-Startup-Zuweisung zugeordnet werden können, erscheinen als inherited. Das umfasst immer /usr/bin, /bin, /usr/sbin und /sbin: Sie sind der Ausgangspunkt, von dem der Tracer startet, nicht etwas, das eine Datei hinzugefügt hat.
--check filtert auf Einträge, deren Verzeichnis nicht mehr existiert, und löst die Quelle erneut gegen deine Dotfiles und /etc/paths.d auf, sodass es auf die zu bearbeitende Zeile zeigt:
$ 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)
Beendet mit 1, wenn tote Einträge gefunden werden, was es in Skripten nutzbar macht.
export EDITOR=vim VISUAL=vim erfasst nur EDITOR.$HOME (.zshenv, .zprofile, .zshrc, .zlogin, .zlogout, .bashrc, .bash_profile, .profile) und deren Varianten im Stil .bak/.old. Sie folgen weder $ZDOTDIR, ~/.config/zsh, /etc noch Dateien, die du sourcest.dangling überspringt PATH-artige Werte und alles mit einer Expansion darin (export GOPATH=$HOME/go); diese kann es statisch nicht auflösen.path-Zuordnung basiert auf xtrace-Diffs. Die erste Zuweisung, die einen Eintrag enthält, beansprucht ihn, selbst wenn er über eine $PATH-Expansion weitergetragen statt explizit hinzugefügt wurde.eval ausgeführt wird, die eval-Zeile plus einen Offset; bash hat keinen Marker für eval-Körper wie zsh.envocabulary wird niemals deine Shell-Konfiguration unseten, rmen oder bearbeiten. Ein Notfallwerkzeug sollte nicht das sein, was den Notfall verschlimmert. Wenn du aufräumen möchtest, kopiere die file:line-Verweise und nimm die Änderungen selbst vor. clean gibt nach stdout aus; die Umleitung machst du.