Skip to content

basename Command Cheat Sheet

basename extracts the filename component from a full path by removing the directory portion. It's particularly useful in shell scripts for file manipulation, name parsing, and generating output filenames.


Synopsis

basename NAME [SUFFIX]
basename OPTION... NAME...

Description

basename strips directory information and optionally a trailing suffix from filenames. It operates on string data and doesn't check if files actually exist.


Basic Usage

Extract Filename

basename /home/user/documents/file.txt

Output: file.txt

Remove Extension

basename /home/user/documents/file.txt .txt

Output: file

Multiple Files

basename -a /path/to/file1.txt /path/to/file2.txt

Output:

file1.txt
file2.txt


Options

-a, --multiple

Process multiple arguments:

basename -a file1.txt file2.txt file3.txt

-s, --suffix=SUFFIX

Remove trailing suffix:

basename -s .txt /home/user/file.txt
# Output: file

-z, --zero

End lines with NUL instead of newline:

basename -z file1.txt file2.txt | xargs -0 echo

Useful with xargs -0 for filenames with spaces.


Common Patterns

Strip Directory

path="/var/log/syslog"
filename=$(basename "$path")
echo $filename  # sys log

Remove Extension

fullname="document.pdf"
basename "$fullname" .pdf  # document

Get Extension

filename="archive.tar.gz"
# Get everything after first dot
extension="${filename#*.}"  # tar.gz

# Get everything after last dot
extension="${filename##*.}"  # gz

Note: Use parameter expansion for extensions, not basename.


Shell Scripting

Process Multiple Files

for file in /path/to/*.txt; do
    name=$(basename "$file" .txt)
    echo "Processing: $name"
done

Rename Files

for file in *.jpeg; do
    newname=$(basename "$file" .jpeg).jpg
    mv "$file" "$newname"
done

Create Output Filenames

input="/data/logs/app.log"
output="/backup/$(basename "$input").bak"
# output="/backup/app.log.bak"

Extract Name in Function

process_file() {
    local filepath="$1"
    local filename=$(basename "$filepath")
    local name=$(basename "$filepath" .txt)

    echo "Full path: $filepath"
    echo "Filename: $filename"
    echo "Name without extension: $name"
}

process_file "/home/user/data.txt"

Advanced Usage

Multiple Extensions

filename="archive.tar.gz"

# Remove .gz
basename "$filename" .gz  # archive.tar

# Remove .tar.gz (doesn't work directly)
# Use parameter expansion instead:
name="${filename%.tar.gz}"  # archive

Strip Multiple Suffixes

for suffix in .txt .log .tmp; do
    name=$(basename "file.txt" $suffix)
done

Processing with Find

find /path -name "*.txt" -exec basename {} .txt \;

Batch Renaming

#!/bin/bash
for file in /source/*.txt; do
    base=$(basename "$file" .txt)
    cp "$file" "/dest/${base}_backup.txt"
done

Practical Examples

Build Script

#!/bin/bash
SOURCE_DIR="/home/user/src"
BUILD_DIR="/home/user/build"

for source in "$SOURCE_DIR"/*.c; do
    name=$(basename "$source" .c)
    gcc "$source" -o "$BUILD_DIR/$name"
    echo "Compiled: $name"
done

Log Rotation

#!/bin/bash
LOGFILE="/var/log/app.log"
ARCHIVE_DIR="/var/log/archive"

logname=$(basename "$LOGFILE")
timestamp=$(date +%Y%m%d_%H%M%S)

mv "$LOGFILE" "$ARCHIVE_DIR/${logname}.$timestamp"
touch "$LOGFILE"

Backup Script

#!/bin/bash
for file in ~/documents/*.pdf; do
    filename=$(basename "$file")
    cp "$file" "/backup/$filename.$(date +%Y%m%d)"
done

Convert File Types

#!/bin/bash
# Convert all .jpeg to .jpg
for file in *.jpeg; do
    [ -f "$file" ] || continue
    base=$(basename "$file" .jpeg)
    convert "$file" "${base}.jpg"
    echo "Converted: $base"
done

Combining with dirname

fullpath="/home/user/documents/file.txt"

dir=$(dirname "$fullpath")   # /home/user/documents
file=$(basename "$fullpath")  # file.txt

echo "Directory: $dir"
echo "Filename: $file"

Reconstruct Path

dir=$(dirname "$path")
file=$(basename "$path")
newpath="$dir/new_$file"

Common Use Cases

Extract Script Name

#!/bin/bash
SCRIPT_NAME=$(basename "$0")
echo "Running: $SCRIPT_NAME"

Generate Temp Files

input_file="/data/input.csv"
temp_file="/tmp/$(basename "$input_file").tmp"

Create Parallel Directory Structure

for file in /source/*/*.txt; do
    dir=$(dirname "$file")
    name=$(basename "$file")
    mkdir -p "/dest/$dir"
    cp "$file" "/dest/$dir/$name"
done

Parse Filename Components

parse_filename() {
    local fullpath="$1"
    local dir=$(dirname "$fullpath")
    local full_name=$(basename "$fullpath")
    local name=$(basename "$fullpath" "${fullpath##*.}")
    local ext="${fullpath##*.}"

    echo "Directory: $dir"
    echo "Full filename: $full_name"
    echo "Name: $name"
    echo "Extension: $ext"
}

parse_filename "/home/user/document.pdf"

Tips and Best Practices

  1. Quote Variables - Always quote paths: basename "$file"
  2. Check File Existence - basename doesn't verify files exist
  3. Use Parameter Expansion - For complex string manipulation
  4. Handle Spaces - Quote all variables to handle spaces in names
  5. Combine with dirname - Often used together for path manipulation
  6. Test Edge Cases - Test with trailing slashes, no extension, etc.
  7. Use -a for Multiple - More efficient than loops
  8. Prefer Shell Builtins - Parameter expansion can be faster
  9. Document Assumptions - Comment what extensions you expect
  10. Error Handling - Check for empty strings and invalid paths

Edge Cases

Trailing Slashes

basename /path/to/dir/
# Output: dir

basename /path/to/dir////
# Output: dir

Trailing slashes are handled correctly.

No Directory

basename file.txt
# Output: file.txt

Root Directory

basename /
# Output: /

Empty String

basename ""
# Output: (empty)

Dot Files

basename /path/to/.hidden
# Output: .hidden

Alternatives

Parameter Expansion (Bash)

path="/home/user/file.txt"

# Instead of basename
filename="${path##*/}"  # file.txt

# Remove extension
name="${filename%.*}"   # file

# More efficient in loops

Using awk

echo "/home/user/file.txt" | awk -F/ '{print $NF}'
# Output: file.txt

Using sed

echo "/home/user/file.txt" | sed 's|.*/||'
# Output: file.txt

Performance

For processing many files, parameter expansion is faster:

# Slower (spawns process)
for file in *; do
    name=$(basename "$file")
done

# Faster (shell builtin)
for file in *; do
    name="${file##*/}"
done

Error Handling

#!/bin/bash
process_file() {
    local file="$1"

    if [ -z "$file" ]; then
        echo "Error: No filename provided" >&2
        return 1
    fi

    local name=$(basename "$file")

    if [ -z "$name" ]; then
        echo "Error: Invalid filename" >&2
        return 1
    fi

    echo "Processing: $name"
}

Integration Examples

With find

find /path -type f -name "*.txt" | while read file; do
    name=$(basename "$file" .txt)
    echo "$name"
done

With xargs

find /path -type f -print0 | \
    xargs -0 -I {} basename {} .txt

With parallel

find /path -type f | parallel basename {} .txt

Comparison Table

Method Speed Portability Complexity
basename Medium High Low
${path##*/} Fast Bash only Medium
awk Medium High Medium
sed Medium High High

Real-World Scripts

Mass File Converter

#!/bin/bash
# Convert all HEIC to JPG
for img in *.HEIC; do
    [ -f "$img" ] || continue
    base=$(basename "$img" .HEIC)
    heif-convert "$img" "${base}.jpg"
    echo "Converted: $base"
done

Organize Downloads

#!/bin/bash
DOWNLOAD_DIR=~/Downloads
ORGANIZED_DIR=~/Documents/Organized

for file in "$DOWNLOAD_DIR"/*; do
    [ -f "$file" ] || continue

    filename=$(basename "$file")
    ext="${filename##*.}"

    mkdir -p "$ORGANIZED_DIR/$ext"
    mv "$file" "$ORGANIZED_DIR/$ext/$filename"
done

Create Backup with Timestamp

#!/bash
backup_file() {
    local source="$1"
    local backup_dir="${2:-/backup}"

    local name=$(basename "$source")
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup="$backup_dir/${name}.$timestamp"

    cp "$source" "$backup"
    echo "Backed up: $backup"
}

backup_file "/etc/nginx/nginx.conf"

Exit Status

Code Meaning
0 Success
1 Error (invalid option, missing argument)

Quick Reference

Command Output
basename /path/to/file.txt file.txt
basename /path/to/file.txt .txt file
basename -a f1.txt f2.txt f1.txt f2.txt (on separate lines)
basename -s .txt file.txt file
basename -z file.txt file.txt\0 (NUL-terminated)