opscape

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...

7 of 7 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: basename(1)

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
explain
output
users.csv

Everything up to and including the last / is removed.

Strip an extension too

basename data/users.csv .csv
explain
output
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
explain
output
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/
explain
output
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 out
for f in data/*.csv; do
  cp "$f" "out/$(basename "$f" .csv).txt"
done
ls out
output
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}"
output
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

tool.sh
#!/bin/bash
echo "usage: $(basename "$0") FILE" >&2
exit 2
bash ./tool.sh
explain
outputexit 2
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 $f breaks on names with spaces. Write basename -- "$f"; the -- also protects names that start with a dash.

  • basename file.tar.gz .gz gives file.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).

  • -a and -s exist in both GNU and BSD/macOS basename; 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.

OptionWhat it does
-a, --multipleTreat every argument as a NAME.
-s, --suffix SUFFIXRemove SUFFIX from each name; implies -a.
-z, --zeroEnd each output line with a NUL byte.

Related