Home / Alt manpages / realpath(1)

  • realpath(1)
  • User command
  • linux

Resolve Linux Paths Safely with realpath

You will use GNU realpath to turn a pathname into an absolute, normalised name, understand what happens to symlinks and .., and choose the right behaviour when a path is missing. The installed command on this machine is GNU coreutils 9.4, from Ubuntu package version 9.4-3ubuntu6.3.

Allow about ten minutes. You need a shell and a path you can read. The examples only inspect names and print results. They do not create, remove or modify files, and they do not need elevated privileges.

1. Check the installed command

Confirm which executable the shell will run, then record its version:

$ command -v realpath
/usr/bin/realpath
$ realpath --version
realpath (GNU coreutils) 9.4

Checkpoint: if command -v prints nothing, realpath is not available through your current PATH. Do not replace it with an unverified script that happens to have the same name. Check your distribution's coreutils package instead.

2. Resolve an ordinary path

Pass one or more pathnames as arguments. By default, every component except the last one must exist, and the default physical mode expands symlinks as it encounters them:

$ realpath /var/log/../log/syslog
/var/log/syslog

The result is written to standard output, one resolved name per input. The command does not change the path on disk. A successful result is a useful value to pass to another command, but it is not proof that the last component is a regular file. A final component may be a directory, a device, or another object allowed by the filesystem.

Use the status immediately after a check if a script needs to distinguish success from failure:

$ realpath /var/log/syslog
/var/log/syslog
$ printf '%s\n' "$?"
0

3. Choose how missing components are handled

The default is a middle ground: parent components must exist, but the final component may be absent. Use --canonicalize-existing when every component, including the last one, must exist:

$ realpath --canonicalize-existing /var/log/syslog
/var/log/syslog
$ realpath --canonicalize-existing /path/that/does/not/exist
realpath: /path/that/does/not/exist: No such file or directory

The second command returns non-zero. In a script, do not use its printed error as the test. Branch on the status and decide whether a missing path is expected.

Use --canonicalize-missing when you are preparing a name before creating it, or when no component is required to exist:

$ realpath --canonicalize-missing /tmp/example/new/../result.txt
/tmp/example/result.txt

This option only calculates a name. It does not create /tmp/example or result.txt. If a later command creates a file, handle that command's permissions and race conditions separately.

Physical resolution is the default, but logical resolution changes when .. is interpreted relative to a symlinked directory. Make a small test tree in a scratch directory if you need to see the difference:

$ work=/tmp/realpath-demo
$ mkdir -p "$work/real/child"
$ ln -s "$work/real" "$work/link"
$ realpath --physical "$work/link/child/../child"
/tmp/realpath-demo/real/child
$ realpath --logical "$work/link/child/../child"
/tmp/realpath-demo/link/child

Here the physical result follows link before resolving the parent reference. Logical mode resolves the .. using the written path first, so the symlink remains in the result. The difference matters when a path crosses a symlinked deployment directory. If you have no deliberate logical-path requirement, the default physical behaviour is usually the less surprising choice.

Warning

The mkdir and ln lines above change state in /tmp. Use a unique scratch directory, and do not point them at a directory containing useful data. If you want to undo this particular test after checking it, remove only that scratch directory with rm -rf -- /tmp/realpath-demo. Review the path before running a recursive removal.

--relative-to=DIR resolves the input and prints its name relative to the supplied directory:

$ realpath --relative-to=/var /var/log/syslog
log/syslog

The base directory is an argument to the calculation, not a directory change. Both the base and the input are resolved for this comparison. If the input is outside the base, the output can contain ...

--relative-base=DIR is useful when you want compact names only for paths below a known tree. Paths below the base are printed relative to it; other paths remain absolute:

$ realpath --relative-base=/var/log /var/log/syslog /etc/hosts
syslog
/etc/hosts

Use --strip, also spelled --no-symlinks, when you want normalised absolute syntax without expanding symlink components:

$ realpath --strip /var/log/../log/syslog
/var/log/syslog

Do not confuse this with checking the physical destination. A stripped result can still name a symlink, so use the default or --physical when the resolved target is what matters.

6. Make scripts quiet and binary-safe

--quiet suppresses most diagnostics, which is useful when a script reports its own error. It does not make an invalid path successful:

if resolved=$(realpath --quiet --canonicalize-existing -- "$input"); then
    printf 'Using %s\n' "$resolved"
else
    status=$?
    printf 'Cannot resolve input (status %s)\n' "$status" >&2
    exit "$status"
fi

The -- marks the end of options, so a filename beginning with a hyphen is treated as a pathname. The example deliberately uses command substitution for a single result. For multiple arbitrary filenames, use --zero and a NUL-aware consumer, because ordinary newline-separated output cannot represent a newline inside a filename safely:

$ realpath --zero -- /path/to/one /path/to/two | od -An -t x1
 2f 70 61 74 68 2f 74 6f 2f 6f 6e 65 00

Do not parse output with whitespace splitting when filenames may contain spaces, tabs or newlines. Also remember that realpath resolves names; it does not grant access. A later open can still fail, and a path can change between resolution and use.

Done means

  • You checked that the installed command is GNU coreutils 9.4 or identified the version you are documenting.
  • You selected default physical resolution, logical resolution, or symlink stripping deliberately.
  • You used --canonicalize-existing for strict existence checks and --canonicalize-missing only when absent components are acceptable.
  • Your script checks the exit status and uses -- before untrusted or hyphen-leading pathnames.
  • You use --zero with a NUL-aware consumer when filenames cannot safely be separated by newlines.