Files and directories
basename
Strip the directory part (and optionally a suffix) from a path, leaving the file name.
basename NAME [SUFFIX] | basename -s SUFFIX -a NAME...
basename takes a path and prints its last component. It works purely on the string: the file
does not have to exist. It is the counterpart of dirname, which prints everything except
the last component.
Inside bash scripts, parameter expansion does the same job without starting a process:
${path##*/} is the basename and ${f%.txt} strips a suffix. That matters in a loop over
thousands of files; for a one-off, basename reads more clearly.
Examples
File name from a path
basename /home/dev/demo/data/users.csv
users.csv
Everything up to and including the last / is removed.
Strip an extension too
basename data/users.csv .csv
users
A second argument is a suffix to remove, if the name ends with it.
Several paths at once
basename -a -s .log logs/app.log logs/error.log
app error
-a accepts several names; -s sets the suffix to strip from each (and implies -a).
Trailing slashes are ignored
basename /home/dev/demo/
demo
A trailing slash does not create an empty last component; the result is demo.
Rename extensions in a loop
Setup run before this example
mkdir outfor f in data/*.csv; do
cp "$f" "out/$(basename "$f" .csv).txt"
done
ls out
sales.txt users.txt
basename "$f" .csv turns data/sales.csv into sales, so each copy gets a .txt name.
Quote both the argument and the command substitution.
The same without a subprocess
f=data/users.csv
name=${f##*/}
echo "$name ${name%.csv}"
users.csv users
${f##*/} deletes the longest prefix ending in /, and ${name%.csv} the suffix. One
difference: with a trailing slash (dir/) the expansion gives an empty string where
basename gives dir.
A script that knows its own name
#!/bin/bash
echo "usage: $(basename "$0") FILE" >&2
exit 2
bash ./tool.sh
usage: tool.sh FILE
$0 is the path the script was started with (./tool.sh); basename turns it into a clean
name for usage messages.
Common pitfalls
Unquoted,
basename $fbreaks on names with spaces. Writebasename -- "$f"; the--also protects names that start with a dash.basename file.tar.gz .gzgivesfile.tar: the suffix is a literal string, not a pattern.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
-aand-sexist in both GNU and BSD/macOSbasename; the long forms (--multiple,--suffix,--zero) are GNU-only.
Options worth knowing
A selection, described in our own words. For the full list, see basename(1) or basename --help.
| Option | What it does |
|---|---|
-a, --multiple | Treat every argument as a NAME. |
-s, --suffix SUFFIX | Remove SUFFIX from each name; implies -a. |
-z, --zero | End each output line with a NUL byte. |
Related
dirnameStrip the last component from a path, leaving the directory part.realpathPrint the absolute, canonical path of a file, with symlinks, . and .. resolved.readlinkPrint where a symbolic link points, or with -f the fully resolved path of any file.- Parameter expansionThe ${...} operators for defaults, lengths, substrings, trimming prefixes and suffixes, search and replace, and case conversion, without calling sed or cut.
- String manipulationLength, substrings, prefix and suffix removal, search and replace, case, trimming, splitting and joining, done with bash's own expansions instead of external tools.