Where to start First steps track · 15 stages
Linux Labs

Paths — basename, dirname, realpath

3 min GNU coreutils

Splitting a path into a name and a directory, getting an absolute path; a script's own directory.

Cheat sheet

5 commands Printable version
  • basename /a/b/c.txt c.txt
  • basename /a/b/c.txt .txt c
  • dirname /a/b/c.txt /a/b
  • realpath ../x an absolute path
  • SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" a script's own directory

Overview

Utilities for treating paths as strings — indispensable in scripts:

  • basename — a file's name without its directory (and, optionally, without an extension).
  • dirname — the directory without the file name.
  • realpath — the absolute path after resolving ., .. and symlinks.
bash
basename /var/log/syslog          # syslog
basename /var/log/app.log .log    # app           (strip the suffix)
dirname  /var/log/syslog          # /var/log
realpath ../../etc/nginx          # /etc/nginx    (absolute, no ../)
realpath -m /nope/x               # compute the path even if it doesn't exist (-m)

Options

6

Each of the three utilities has its own small set of options. basename -s strips a suffix without a separate sed call, -a takes several paths at once. realpath -e requires the whole path to actually exist, while -m does the opposite — it computes the path as a plain string even if the file doesn't exist yet; confusing the two is a common source of bugs in scripts that prepare a path for a file they're about to create themselves.

Option What it does Example
-m --canonicalize-missing realpath: compute the path even if it, or part of it, does not exist. realpath -m /nope/x
-s --suffix SUFFIX basename: strip the given suffix from the name. basename -s .txt /a/b/c.txt
-e --canonicalize-existing realpath: require the whole path to exist; otherwise fail. realpath -e /etc/hosts
-s --strip realpath: do not resolve symlinks, only . and ... realpath -s ../x
-a --multiple basename: multiple names at once, each on its own line. basename -a /a/x /b/y
-z --zero Separate output entries with a NUL byte instead of a newline. basename -z /a/b/c.txt

Nothing found. Try a shorter query.

Recipes

1

In scripts

The classic case is finding the script's own directory, so paths don't depend on where it was run from:

bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"     # portable
# or shorter, with realpath:
SCRIPT_DIR="$(dirname "$(realpath "$0")")"

Splitting a path into parts:

bash
path=/srv/www/site/index.html
dir=$(dirname  "$path")           # /srv/www/site
base=$(basename "$path")          # index.html
name=$(basename "$path" .html)    # index

Plain bash gives you the same thing with parameter expansion: ${path##*/} (basename) and ${path%/*} (dirname) — no external program needed. See bash-scripting.

Troubleshooting

3

A path with spaces "fell apart"

Always quote it: dirname "$path". Without quotes, a space splits the arguments.

realpath: No such file or directory

By default, realpath requires the path to exist. For a path that doesn't exist yet, use -m (compute it as a plain string) or -e (the opposite — require every component to exist).

You need the path without resolving symlinks

realpath follows symlinks. To leave it as-is, use realpath -s (or readlink for the link itself, see ln).

Terms

2
absolute path
A path that starts with / and locates a file from the filesystem root; its meaning does not depend on the current directory. Example: /etc/ssh/sshd_config. Also appears in: at, Cron, ln
relative path
A path without a leading / that is resolved from the process's current directory. The components . and .. refer to the directory itself and its parent. Also appears in: systemd timers, ln, ls, tar

See also

  • files-basics — Navigation and files — ls, cd, cp, mv, rm, cat, less, head, tail, copy-paste in the terminal.
  • cd — Moving around the filesystem: cd, cd -, cd ~, cd .., pushd/popd, CDPATH.
  • bash-scripting — Variables, conditionals, loops, arguments and the safe set -euo pipefail mode.
Loading…