Skip to content
shellmap

resolve-pathCanonicalize a path — realpath equivalent across all 5 shells

Equivalents in every shell

Bashunix
realpath -e file.txt

`realpath` is GNU coreutils (Linux default). `-e` requires every component to exist; `-m` permits non-existent (good for "what would the absolute path be"); `-s` does NOT resolve symlinks (lexical only). On macOS, `realpath` arrived in 12+; older Macs use `greadlink -f` from coreutils-via-brew.

Zshunix
echo ${file:A}

zsh has the `:A` modifier on parameter expansion — `${file:A}` resolves symlinks AND canonicalises (closest to GNU `realpath -e`). `${file:a}` is lexical-only (closer to `realpath -s`). No external command needed; faster than `realpath` for one-off use. macOS bash users without coreutils often shell out to `pwd -P` after `cd`.

Fishunix
path resolve file.txt

Fish-native `path resolve file.txt` (since fish 3.5) — built-in, no fork, returns absolute path with symlinks resolved. `path` is fish's general-purpose path manipulation builtin (also `path basename`, `path dirname`, `path extension`). External `realpath` also works on systems that ship it.

PowerShellwindows
Resolve-Path file.txt

PowerShell-native cmdlet. Returns a `[PathInfo]` object — `.Path` is the full string; `.Provider` is the PS provider. THROWS a terminating error if the path does not exist (unlike `realpath -m`). For non-existent paths use `[System.IO.Path]::GetFullPath((Join-Path (Get-Location) "missing.txt"))` (lexical, never throws).

cmd.exewindows
for %i in (file.txt) do @echo %~fi

No native `realpath`. The closest idiom is `%~dpnx<arg>` which expands argument N to its full Drive-Path-Name-eXtension form — but only inside a batch file, not interactive. `for %i in (file.txt) do @echo %~fi` is the interactive workaround (`%~fi` = full path). Neither follows symlinks; for that, PowerShell or WSL.

Worked examples

Get the absolute path of a relative file

Bash
realpath ./config.json
Zsh
file=./config.json; echo ${file:A}
Fish
path resolve ./config.json
PowerShell
Resolve-Path ./config.json
cmd.exe
for %i in (config.json) do @echo %~fi

Resolve a symlink to its real target

Bash
realpath -e /usr/bin/python3
Zsh
file=/usr/bin/python3; echo ${file:A}
PowerShell
(Get-Item /usr/bin/python3).Target

Compute an absolute path even when the file does not exist

Bash
realpath -m ./not-yet-created.txt
PowerShell
[System.IO.Path]::GetFullPath((Join-Path (Get-Location) "not-yet-created.txt"))

Gotchas

  • `Resolve-Path` THROWS a terminating error (`Cannot find path because it does not exist`) if the path does not exist — surprising to bash users used to `realpath -m`. The two clean workarounds: `Resolve-Path missing.txt -ErrorAction SilentlyContinue` (returns `$null`), or `[System.IO.Path]::GetFullPath((Join-Path $PWD 'missing.txt'))` (lexical, never throws). Pick based on whether you need symlink-resolution.
  • `Resolve-Path` returns ALL paths matching its wildcards — `Resolve-Path *.log` returns multiple `[PathInfo]` objects. Iterate or pull `.Path`. This trips bash users who expect a single string back like `realpath`.
  • macOS shipped `realpath` in 12+ (Monterey); on older macOS the standard binary did NOT exist. `readlink -f` (GNU style) ALSO does not exist on BSD/macOS — BSD `readlink` is one-hop only. The portable macOS-and-Linux idiom is `cd "$(dirname "$f")" && pwd -P` followed by `basename`, OR install coreutils-via-brew (`greadlink -f`).
  • The zsh `${file:A}` modifier resolves AS-IF the file is in the current directory — this means relative `./foo` resolves correctly, but a bare `foo` (no leading `./`) is treated as a name, not a path, and may NOT resolve as expected. Always pass `./foo` or `$PWD/foo` to `:A` for a leading path; or use the more explicit `${(:-./foo):A}` form.
  • `Resolve-Path` on a UNC path (`\\server\share\file`) requires the share to be REACHABLE — it actively touches the network. For pure-string canonicalisation (no I/O), `[System.IO.Path]::GetFullPath` is the right tool; for UNC scripting that should not block on offline shares, wrap in `Test-Path -ErrorAction SilentlyContinue` first.

WSL & PowerShell Core notes

pwsh`Resolve-Path` works on every pwsh platform — Windows, macOS, Linux — against the file-system provider. On Windows it follows NTFS junctions and symlinks; on Linux/macOS it follows POSIX symlinks. The behaviour matches the platform-native `realpath` semantics, so cross-platform scripts get the correct OS-specific resolution for free.
WSLInside WSL, `realpath /mnt/c/Users/me/file.txt` returns the WSL Linux-style path. From Windows pwsh, `Resolve-Path \\wsl$\Ubuntu\home\me\file.txt` returns the UNC form. There is NO direct path translation between the two — for that, `wslpath -w /mnt/c/foo` (Linux → Windows) and `wslpath -u C:\foo` (Windows → Linux) are the canonical converters.

Related commands