Show the file path of a command
Print where on the filesystem a command resolves to — for debugging PATH issues, version mismatches, and "which python is this".
How to show the file path of a command in each shell
which lsExternal `/usr/bin/which` (POSIX). Bash has a `type` builtin that's more informative: `type ls` shows alias / function / builtin / file. `type -a ls` shows ALL definitions in resolution order.
which lsZsh `which` is a FUNCTION that wraps `whence -c`. UNLIKE POSIX `which`, zsh `which ls` shows the ALIAS DEFINITION if `ls` is aliased (e.g. `ls: aliased to ls --color=auto`). For raw path use `whence -p ls`.
which lsFish `which` is fish-native (calls `command -v`). Like bash POSIX `which` it shows the file path, NOT the alias expansion. For alias-aware lookup: `functions ls` (fish aliases ARE functions).
Get-Command lsReturns a rich `[CommandInfo]` object with `Source` (file path or alias target), `CommandType` (Alias / Cmdlet / Function / Application), `Version`. Multi-match: `Get-Command ls -All`.
where lscmd `where` (Windows native, not a POSIX-clone) searches PATH + current dir + Windows registry App Paths. Returns ALL matches one per line. For doskey macros: `doskey /macros | findstr ls`.
Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.
Gotchas & notes
- **`which` is THREE different binaries** depending on shell: (1) bash without builtin → external `/usr/bin/which` (POSIX — file path only, ignores aliases/functions); (2) zsh → SHELL FUNCTION that wraps `whence -c` (alias-aware, shows expansion); (3) fish → fish builtin (file path only). Same name, different behavior, same input. The CONSISTENT cross-shell answer is `type -a` (bash/zsh) or `command -v` (POSIX-portable, ignores aliases/functions, prints only the resolved name+path). Modern guidance from the Linux Standard Base and POSIX is to PREFER `command -v` over `which` — `which` isn't in POSIX at all (it's ubiquitous-but-non-standard).
- pwsh `Get-Command` is the most informative — returns objects, not strings. `Get-Command ls` → `CommandType=Alias, Source=Get-ChildItem`. `Get-Command Get-ChildItem` → `CommandType=Cmdlet, ModuleName=Microsoft.PowerShell.Management`. `Get-Command notepad` → `CommandType=Application, Source=C:\Windows\System32\notepad.exe`. `Get-Command ls -All` shows EVERY override in priority order (alias > function > cmdlet > application — pwsh's resolution order). For "is this command even available": `Get-Command foo -ErrorAction SilentlyContinue` returns `$null` if not found.
- macOS-specific: `/usr/bin/which` is the BSD version (different from GNU which). On Apple Silicon Macs, Homebrew installs to `/opt/homebrew/bin` vs Intel Macs `/usr/local/bin` — `which brew` returning different paths is the canonical "wrong PATH order" detection. Rosetta-emulated x86_64 shells see `/usr/local` first; native arm64 shells see `/opt/homebrew` first. `arch -arm64 which python3` vs `arch -x86_64 which python3` reveals this. The dual-Homebrew situation is the single most-confusing macOS aspect of `which` debugging.
- `type -a` is the GOLD-STANDARD debugger for "why is this command misbehaving": `type -a ls` on bash returns ALL definitions: e.g. `ls is aliased to \'ls --color=auto\'` + `ls is /usr/bin/ls`. This tells you both the override (alias wins) AND the underlying file. Zsh `type -a ls` shows the same. fish equivalent: `type --all ls`. pwsh: `Get-Command ls -All` lists everything. cmd has nothing equivalent — `where ls` only finds executables, never doskey macros or PATHEXT extensions; manually check `doskey /macros` first, then `where`.
Related commands
Related tasks
- Detect the current shell— Determine which shell (bash / zsh / fish / pwsh / cmd) is currently running — for conditional dotfile loading and script-detection scenarios.
- List all shell aliases— Print every alias currently defined in the shell — for debugging "why does `ls` behave differently here" and auditing dotfiles.
- Prepend a directory to PATH— Add a directory to the FRONT of PATH so commands inside it override system equivalents — for tool-version pinning (node@18 vs system node) and local-bin priorities.
- Source an env file into the current shell— Load variables from a `.env`-style file into the current shell session — for project-specific secrets, dev-mode flags, and tool-version locks.