How to Rename File Extensions
β’ 2 min read
bash
Quick Answer: Rename File Extensions in Bash
To rename a file extension, use mv: mv file.txt file.md. For batch renaming, use a loop with parameter expansion: for f in *.txt; do mv "$f" "${f%.txt}.md"; done. The ${f%.txt} syntax removes the old extension.
Quick Comparison: File Extension Renaming Methods
| Method | Syntax | Batch | Best For |
|---|---|---|---|
| mv | mv file.old file.new | Single | One file |
| for loop + mv | for f in *.old; do mv ... done | Yes | Simple batch |
| rename command | rename 's/\.old$/.new/' *.old | Yes | Bulk rename |
| sed + xargs | ls *.old | sed ... | Yes | Piped renaming |
| find + exec | find . -name "*.old" -exec ... | Yes | Complex patterns |
Bottom line: Use loops for simple batch renaming, use rename for complex patterns.
Rename file extensions in batch using bash parameter expansion, loops, and tools like rename. Learn single and bulk renaming.
Simple Extension Rename with mv
# Rename single file
mv file.txt file.md
# Using parameter expansion for extension
file="document.txt"
newfile="${file%.txt}.md"
mv "$file" "$newfile"
Rename Multiple Files
# Rename all .txt files to .md
for file in *.txt; do
mv "$file" "${file%.txt}.md"
done
This removes .txt and adds .md to each file.
Detailed Example with Output
Test files:
report.txt
notes.txt
summary.txt
# Rename all .txt to .md
for file in *.txt; do
newfile="${file%.txt}.md"
mv "$file" "$newfile"
echo "Renamed: $file β $newfile"
done
Output:
Renamed: report.txt β report.md
Renamed: notes.txt β notes.md
Renamed: summary.txt β summary.md
Parameter Expansion for Extensions
#!/bin/bash
file="document.pdf"
# Remove extension (everything from last dot)
name="${file%.*}"
echo "Name: $name" # Output: document
# Get just extension
extension="${file##*.}"
echo "Extension: $extension" # Output: pdf
# Replace extension
new_extension="docx"
newfile="${name}.${new_extension}"
echo "New file: $newfile" # Output: document.docx
Function for Extension Renaming
#!/bin/bash
rename_extension() {
local file="$1"
local old_ext="$2"
local new_ext="$3"
if [ ! -f "$file" ]; then
echo "ERROR: File not found: $file"
return 1
fi
# Check if file has the old extension
if [[ ! "$file" =~ \.$old_ext$ ]]; then
echo "ERROR: File doesn't end with .$old_ext"
return 1
fi
# Get basename without extension
name="${file%.*}"
# Create new filename
newfile="${name}.${new_ext}"
# Perform rename
if mv "$file" "$newfile"; then
echo "β Renamed: $file β $newfile"
else
echo "β Failed to rename: $file"
return 1
fi
}
# Usage
rename_extension "document.txt" "txt" "md"
Batch Rename in Directory
#!/bin/bash
# File: batch_rename.sh
directory="${1:-.}"
old_ext="${2:-.txt}"
new_ext="${3:-.md}"
if [ ! -d "$directory" ]; then
echo "ERROR: Directory not found: $directory"
exit 1
fi
count=0
for file in "$directory"/*$old_ext; do
if [ -f "$file" ]; then
# Get directory and filename
dir=$(dirname "$file")
basename=$(basename "$file")
name="${basename%.*}"
newfile="$dir/${name}.${new_ext}"
if mv "$file" "$newfile"; then
echo "β $basename β $(basename $newfile)"
((count++))
fi
fi
done
echo ""
echo "Renamed $count files"
Usage:
$ chmod +x batch_rename.sh
$ ./batch_rename.sh . txt md
Output:
β file1.txt β file1.md
β file2.txt β file2.md
β file3.txt β file3.md
Renamed 3 files
Using the βrenameβ Tool
# If rename command is available
rename 's/\.txt$/.md/' *.txt
# Rename with regex pattern
rename 's/old_name/new_name/' old_name.*
# Safely preview changes (dry-run)
rename -n 's/\.txt$/.md/' *.txt
# Create backups of renamed files
rename -b 's/\.txt$/.md/' *.txt
Rename with Conditions
#!/bin/bash
# Only rename files smaller than 1MB
directory="."
max_size=$((1024 * 1024)) # 1MB
for file in "$directory"/*.txt; do
if [ -f "$file" ]; then
size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null)
if [ "$size" -lt "$max_size" ]; then
newfile="${file%.txt}.bak"
mv "$file" "$newfile"
echo "Backed up: $(basename $file) β $(basename $newfile)"
fi
fi
done
Case Conversion in Extension
#!/bin/bash
# Convert extension to lowercase
for file in *; do
if [ -f "$file" ]; then
# Get name and extension
name="${file%.*}"
ext="${file##*.}"
# Convert to lowercase
lower_ext=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
# Rename if different
if [ "$ext" != "$lower_ext" ]; then
newfile="${name}.${lower_ext}"
mv "$file" "$newfile"
echo "Changed: $file β $newfile"
fi
fi
done
Example (before):
Document.TXT
Image.JPEG
Data.CSV
Example (after):
Document.txt
Image.jpeg
Data.csv
Safe Rename with Backup
#!/bin/bash
# Rename with automatic backup creation
file="$1"
old_ext="$2"
new_ext="$3"
if [ ! -f "$file" ]; then
echo "ERROR: File not found"
exit 1
fi
# Create backup
cp "$file" "${file}.backup"
echo "Backup created: ${file}.backup"
# Rename
newfile="${file%.$old_ext}.$new_ext"
mv "$file" "$newfile"
echo "Renamed: $file β $newfile"
echo "Original backup: ${file}.backup"
Rename with Logging
#!/bin/bash
# Log all rename operations
log_file="rename_log.txt"
old_ext="$1"
new_ext="$2"
{
echo "=== Rename Operation ==="
echo "Date: $(date)"
echo "From: .$old_ext β .$new_ext"
echo ""
} >> "$log_file"
for file in *$old_ext; do
if [ -f "$file" ]; then
newfile="${file%.*}.${new_ext}"
mv "$file" "$newfile"
echo "$file β $newfile" >> "$log_file"
fi
done
echo "Log saved to: $log_file"
Recursive Rename in Subdirectories
#!/bin/bash
# Rename files in all subdirectories
old_ext="$1"
new_ext="$2"
if [ -z "$old_ext" ] || [ -z "$new_ext" ]; then
echo "Usage: $0 <old_ext> <new_ext>"
exit 1
fi
find . -type f -name "*$old_ext" | while read file; do
newfile="${file%.*}.${new_ext}"
mv "$file" "$newfile"
echo "Renamed: $file"
done
echo "β Batch rename complete"
Error Handling and Validation
#!/bin/bash
rename_with_validation() {
local file="$1"
local new_ext="$2"
# Validation
if [ ! -f "$file" ]; then
echo "ERROR: File not found: $file"
return 1
fi
if [ -z "$new_ext" ]; then
echo "ERROR: No extension provided"
return 1
fi
# Create new filename
name="${file%.*}"
newfile="${name}.${new_ext}"
# Check if target already exists
if [ -f "$newfile" ]; then
echo "ERROR: Target file already exists: $newfile"
return 1
fi
# Perform rename
if mv "$file" "$newfile" 2>/dev/null; then
echo "β Renamed: $file β $newfile"
return 0
else
echo "β Failed to rename: $file"
return 1
fi
}
# Usage
rename_with_validation "document.txt" "md"
Common Mistakes
- Forgetting quotes - fails with spaces:
mv $file $newfilevsmv "$file" "$newfile" - Wrong parameter expansion -
${file%.txt}removes from right,${file#*/}from left - Not checking if file exists - rename fails silently
- Case sensitivity -
.TXTβ.txt - Hidden files - remember to handle dotfiles
Performance Tips
- Test with a few files first
- Use dry-run before actual rename
- Keep backups of important files
- Log operations for auditing
- Consider using
findfor recursive operations
Key Points
- Use
${file%.*}to get name without extension - Use
${file##*.}to get just extension - Always quote variables in loops
- Test with small dataset first
- Keep backups of important files
Summary
Renaming file extensions in bulk is straightforward with bash parameter expansion. Always validate input, test carefully, and keep backups. The rename tool offers more features if available on your system.