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
- Quote Variables - Always quote paths:
basename "$file" - Check File Existence - basename doesn't verify files exist
- Use Parameter Expansion - For complex string manipulation
- Handle Spaces - Quote all variables to handle spaces in names
- Combine with dirname - Often used together for path manipulation
- Test Edge Cases - Test with trailing slashes, no extension, etc.
- Use -a for Multiple - More efficient than loops
- Prefer Shell Builtins - Parameter expansion can be faster
- Document Assumptions - Comment what extensions you expect
- 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) |