env — Print current environment variables or run a command in a clean env across all 5 shells
Equivalents in every shell
envExternal binary from coreutils. With no args, dumps every exported variable, one `KEY=VALUE` per line. `env -i bash` starts a fresh bash with an EMPTY environment (useful for reproducing "works on my machine" bugs caused by stray vars). `env FOO=bar mycommand` runs `mycommand` with `FOO` set, without polluting the calling shell. `env -u FOO mycommand` runs without `FOO`. Shell variables that haven't been `export`ed do NOT appear in `env` — they're shell-local, not environment.
envSame external. Zsh quirk: `typeset` and `declare` are zsh's introspection tools — `typeset -x` lists exported (environment) vars with their flags; `typeset` alone lists shell-local vars `env` won't see. `printenv` is the closely-related coreutils command (slightly different — sees only env, no `-i` / `-u` flags). For a per-command env override that zsh history can replay verbatim, `FOO=bar mycommand` (without `env`) also works.
envSame external. Fish stores variables differently from POSIX shells — `set -x FOO bar` exports (visible to `env`), `set FOO bar` is fish-local (NOT in `env`). `set -gx` is global+exported. `env | grep PATH` to inspect specific vars from the env. Fish's own `env --help` shows the coreutils binary's help, not anything fish-specific.
Get-ChildItem Env:The `Env:` PSDrive exposes environment variables as objects — `Get-ChildItem Env:` (alias `gci env:` or `ls env:`) lists them all; `$env:PATH` reads one; `$env:FOO = "bar"` sets one for the current session (NOT persisted — see `[Environment]::SetEnvironmentVariable` with the `User` / `Machine` scope for that). `Get-ChildItem Env: | Sort-Object Name` for an alphabetised view. There is no native pwsh `env -i` — to start a clean-environment subprocess, use `Start-Process pwsh -ArgumentList "-NoProfile","-NoLogo"` and rely on profile / config to define what you want.
set`set` (no args) lists every environment variable. `set FOO` lists vars starting with `FOO`. `set FOO=bar` sets one for the current cmd session (cleared on exit). For persistent set use `setx FOO bar` (writes to the user registry, takes effect in NEW cmd sessions — does NOT affect the current one). `set FOO=` (empty value) unsets in-session. There is no native cmd analog to `env mycommand FOO=bar` — wrap with `set FOO=bar & mycommand` (sets in current session) or use pwsh.
Worked examples
Show all environment variables
envenvenvGet-ChildItem Env:setRun a command with one variable temporarily overridden
env DEBUG=1 npm testenv DEBUG=1 npm test$env:DEBUG = "1"; npm test; Remove-Item Env:DEBUGset DEBUG=1 && npm test && set DEBUG=Start a subprocess with a completely empty environment
env -i bashenv -i fishStart-Process pwsh -ArgumentList "-NoProfile"Gotchas
- Shell variables and environment variables are NOT the same. `FOO=bar` (bash, no `export`) sets a SHELL-LOCAL variable that won't appear in `env` and won't be inherited by subprocesses. `export FOO=bar` (bash) or `set -x FOO bar` (fish) makes it part of the environment. The same trap exists in pwsh: `$FOO = "bar"` is a session var; `$env:FOO = "bar"` is the environment.
- pwsh `$env:FOO = "bar"` is session-only — closing the terminal loses it. For PERSISTENT, use `[Environment]::SetEnvironmentVariable("FOO", "bar", "User")` (registry-backed, available in future sessions) or `"Machine"` scope (HKLM, requires admin, affects all users). The same applies to `cmd` `set` (session) vs `setx` (persistent registry write).
- On Windows, `Path` is the conventional env-var name (mixed case); on Unix, `PATH` (all caps). pwsh `$env:PATH` and `$env:Path` both work because Windows env vars are case-insensitive. On WSL / Linux pwsh, they're case-sensitive — `$env:PATH` succeeds, `$env:Path` may return `$null`. Use the all-caps form for portable scripts.
- cmd `set FOO=bar & mycommand` runs `mycommand` with `FOO=bar`, but the trailing `& set FOO=` is mandatory if you don't want `FOO` to leak into subsequent commands in the same cmd window. The bash `env FOO=bar mycommand` form is automatic — the var only exists for that one process. cmd does NOT have an equivalent one-shot syntax.
- `env` (the binary) is ALSO the shebang interpreter — `#!/usr/bin/env python3` looks up `python3` on `$PATH` rather than hard-coding `/usr/bin/python3`. This is the portable way to write Unix scripts. The shebang does NOT respect alias / function definitions — it only does a `$PATH` lookup. If `python3` is a shell function, the shebang line won't find it.
WSL & PowerShell Core notes
Related glossary
Common tasks using env
- Set an environment variable persistently
Make an environment variable available in every NEW shell session (not just the current one) — for setting `JAVA_HOME`, adding to `PATH`, configuring API tokens for daily-use scripts.
- Show environment variables
List the environment variables visible to the current shell — for debugging "why isn't $FOO set", auditing what subprocesses will inherit, and discovering platform-injected variables (`$HOME`, `$PATH`, `$PSModulePath`).