realpath — Resolve a path to its absolute, canonical form across all 5 shells
Equivalents in every shell
realpath ./symlinkExternal (GNU coreutils on Linux; macOS via `brew install coreutils` provides `grealpath`). Resolves all symlinks and `..` segments to produce a canonical absolute path. `-s` / `--no-symlinks` skips symlink resolution; `-m` allows the target to be missing.
realpath ./symlinkSame external binary. Zsh's `${param:A}` parameter expansion does the same in pure shell: `print -r ${path:A}` canonicalises without spawning a process. Use `:P` (zsh 5.3+) for safer "physical path" semantics.
realpath ./symlinkExternal binary. Fish 3.6+ also ships `path resolve`: `path resolve ./symlink` does the same canonicalisation without launching `realpath` — faster for tight loops.
Resolve-Path ./symlinkReturns a `PathInfo` whose `.Path` is the absolute, cwd-resolved path. For symlink target resolution use `(Get-Item ./symlink).Target` (Windows 10 1607+). `[System.IO.Path]::GetFullPath($p)` works even on paths that do not yet exist.
for %i in (".\file") do @echo %~fiNo `realpath`. The `%~f` modifier inside a `for` loop expands to the full path of a parameter. Symlinks are NOT resolved — use PowerShell's `Resolve-Path` or `(Get-Item ...).Target` for that.
Worked examples
Print the absolute path of a relative reference
realpath ./script.shprint -r ${./script.sh:A}realpath ./script.sh(Resolve-Path ./script.sh).Pathfor %i in (.\script.sh) do @echo %~fiResolve a symlink to its target
realpath /usr/bin/python3path resolve /usr/bin/python3(Get-Item /usr/bin/python3).TargetGet the directory containing the running script
SCRIPT_DIR=$(dirname "$(realpath "$0")")SCRIPT_DIR=${0:A:h}$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.PathGotchas
- macOS does NOT ship `realpath` in the base system on older versions — it arrived with newer BSD coreutils but may be missing on legacy installs. Scripts must either depend on `brew install coreutils` + `grealpath`, or use a portable fallback: `python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$path"`.
- `realpath` REQUIRES the target to exist by default. Use `realpath -m` (or `--canonicalize-missing`) to canonicalise a path that does NOT yet exist — useful when computing "where will this file be written" without first creating it.
- Zsh `${path:A}` (capital A) resolves symlinks; `${path:a}` (lowercase) does NOT — it only collapses `.` and `..` lexically. The one-character difference is a frequent bug source. `:P` (zsh 5.3+) is a safer alias for physical-path resolution.
- PowerShell `Resolve-Path` THROWS if the path does not exist. Use `[System.IO.Path]::GetFullPath($p)` (works on missing paths) when you only need string canonicalisation, not symlink resolution. The two methods produce different results on real symlinks — pick deliberately.
- `realpath` collapses `..` AFTER resolving symlinks, so the result may NOT contain the literal path segments you wrote. `cd /tmp; realpath link/../other` resolves `link` first then strips the `..` — easy to misread as `/tmp/other` when the actual result depends on the link target.