basename — Strip directory part from a path, keeping only the filename across all 5 shells
Equivalents in every shell
basename /var/log/syslogPrints `syslog`. Optional 2nd arg strips a suffix: `basename foo.txt .txt` → `foo`. POSIX-mandated, present on every Unix.
basename /var/log/syslogSame external `basename` binary. Zsh also has the `:t` parameter modifier as a builtin: `${path:t}` returns the tail without forking — faster in tight loops.
basename /var/log/syslogSame external binary. Fish exposes `path basename /var/log/syslog` as a builtin (fish 3.5+) that handles multiple paths and an explicit `--extension` flag for suffix stripping.
Split-Path -Leaf "C:\Windows\System32\drivers\etc\hosts"`-Leaf` returns the last component. `[System.IO.Path]::GetFileName(...)` is the .NET equivalent. To strip the extension as well, chain `-LeafBase` (pwsh 6+) or use `[IO.Path]::GetFileNameWithoutExtension(...)`.
for %I in ("C:\Windows\System32\drivers\etc\hosts") do @echo %~nxINo native `basename`. The `%~nx` variable modifier on a `for` loop variable returns name+extension. Use `%~n` for name-only (no extension), `%~x` for extension-only.
Worked examples
Get the filename portion of a path
basename /usr/local/bin/nodebasename /usr/local/bin/nodeSplit-Path -Leaf "C:\Program Files\nodejs\node.exe"for %I in ("C:\Program Files\nodejs\node.exe") do @echo %~nxIStrip both directory AND a known suffix (e.g. `.tar.gz` → bare name)
basename release-2026.tar.gz .tar.gzpath basename --extension .tar.gz release-2026.tar.gz[IO.Path]::GetFileNameWithoutExtension("release-2026.tar.gz") -replace "\.tar$",""for %I in ("release-2026.tar.gz") do @echo %~nIBatch-rename: for each `.bak` file, print its base without suffix
for f in *.bak; do basename "$f" .bak; donefor f in *.bak; path basename --extension .bak $f; endGet-ChildItem *.bak | ForEach-Object { $_.BaseName }for %I in (*.bak) do @echo %~nIGotchas
- Trailing slashes are stripped: `basename /var/log/` → `log`, not the empty string. This contradicts intuition for "leaf component" — if you need empty-on-dir-slash semantics, check the string explicitly first.
- POSIX `basename` only takes ONE path at a time. GNU coreutils 8.16+ added `-a` for multiple args (`basename -a /a/b /c/d` → two lines), but BusyBox/Alpine and macOS BSD versions don't support it — scripts that must run on Alpine should loop instead of relying on `-a`.
- `basename` with a suffix arg is a string-suffix match, NOT extension-aware. `basename foo.txt .txt` works, but `basename foo.TXT .txt` returns `foo.TXT` (case-sensitive). Use `basename "${f,,}"` (bash lowercasing) or normalise filenames first.
- PowerShell `Split-Path` on a forward-slash path on Windows mostly works (the API normalises) but mixed `\` and `/` in the same string can confuse `Split-Path -Leaf` — prefer `[IO.Path]::GetFileName(...)` for cross-OS robustness in pwsh 7+.
- cmd `%~nxI` works only inside a `for /f` or `for %I` loop — there's no direct expansion outside a loop. Workarounds use a transient single-iteration `for ("path")` like the example above, which is the idiomatic cmd trick.