Perl Rename - Batch File Operations

Perl-Rename - Batch File Renaming with Regex

Purpose

Batch rename files using Perl regular expressions. Far more powerful than basic mv or rename from util-linux.

Installation

Arch Linux

yay -S perl-rename
# or
sudo pacman -S perl-rename

Debian/Ubuntu

sudo apt install rename

Fedora

sudo dnf install prename

macOS

brew install rename

Syntax

perl-rename [options] 's/PATTERN/REPLACEMENT/[flags]' FILE(S)

Options

OPTION          DESCRIPTION
────────────────────────────────────────────────────────────────
-n, --dry-run   Show what would be renamed (NO CHANGES)
-v, --verbose   Print names of renamed files
-f, --force     Overwrite existing files
-i, --interact  Prompt before overwrite
-d, --filename  Only rename filename (not directory path)
-e EXPR         Multiple expressions (can repeat)

Core Operations

Basic Substitution

# Replace 'foo' with 'bar' in filenames
perl-rename 's/foo/bar/' *.txt

# Global replace (all occurrences)
perl-rename 's/foo/bar/g' *.txt

# Case-insensitive replace
perl-rename 's/foo/bar/i' *.txt

Remove Characters

# Remove spaces from filenames
perl-rename 's/ //g' *

# Remove special characters
perl-rename 's/[!@#$%^&*()]//g' *

# Remove leading numbers
perl-rename 's/^\d+[-_]?//' *

Change Case

# Lowercase entire filename
perl-rename 'y/A-Z/a-z/' *

# Uppercase entire filename
perl-rename 'y/a-z/A-Z/' *

# Capitalize first letter
perl-rename 's/^./\u$&/' *

# Lowercase extension only
perl-rename 's/\.([A-Z]+)$/.\L$1/' *

Number Operations

# Remove dots from version numbers: 1.1 -> 11
perl-rename 's/(\d+)\.(\d+)/$1$2/' *

# Zero-pad numbers: 1.txt -> 001.txt
perl-rename 's/(\d+)/sprintf("%03d",$1)/e' *

# Add sequence numbers
perl-rename 'our $i; s/^/sprintf("%03d_", ++$i)/e' *

# Extract and reformat numbers
perl-rename 's/file(\d+)\.txt/document_$1.txt/' *

Extension Operations

# Change extension
perl-rename 's/\.txt$/.md/' *.txt

# Add extension
perl-rename 's/$/.bak/' *

# Remove extension
perl-rename 's/\.[^.]+$//' *

# Double extension handling
perl-rename 's/\.tar\.gz$/.tgz/' *.tar.gz

Pattern Capture Groups

# Swap parts: foo-bar.txt -> bar-foo.txt
perl-rename 's/(\w+)-(\w+)/$2-$1/' *

# Reorder date: 2024-01-15 -> 15-01-2024
perl-rename 's/(\d{4})-(\d{2})-(\d{2})/$3-$2-$1/' *

# Extract and restructure
perl-rename 's/IMG_(\d{4})(\d{2})(\d{2})_(\d+)/photo_$1-$2-$3_$4/' *.jpg

Real-World Examples

Photo Organization

# iPhone photos: IMG_1234.JPG -> 2024-01-15_1234.jpg
perl-rename 's/IMG_(\d+)\.JPG/2024-01-15_$1.jpg/i' *.JPG

# Lowercase all extensions
perl-rename 's/\.(JPG|PNG|GIF)$/.\L$1/' *

# Remove camera prefix
perl-rename 's/^DSC_//' *.jpg

Code Files

# Convert snake_case to kebab-case
perl-rename 's/_/-/g' *.py

# Add prefix to all files
perl-rename 's/^/project_/' *.js

# Version bump: v1.2.3 -> v1.2.4
perl-rename 's/v(\d+)\.(\d+)\.(\d+)/sprintf("v%d.%d.%d",$1,$2,$3+1)/e' *

Log Files

# Add date prefix to logs
perl-rename 's/^/$(date +%Y%m%d)_/' *.log

# Rotate logs: app.log -> app.log.1
perl-rename 's/\.log$/.log.1/' app.log

# Compress old logs pattern
perl-rename 's/\.log\.(\d+)$/".log." . ($1+1)/e' *.log.*

Cleanup Operations

# Replace spaces with underscores
perl-rename 's/ /_/g' *

# Remove parentheses and contents
perl-rename 's/\s*\([^)]*\)//' *

# Clean URL-encoded names
perl-rename 's/%20/ /g; s/%28/(/g; s/%29/)/g' *

# Remove duplicate extensions
perl-rename 's/(\.\w+)\1$/$1/' *

Batch Processing with Find

# Rename in subdirectories
find . -name "*.txt" -exec perl-rename 's/old/new/' {} \;

# Recursive lowercase
find . -depth -exec perl-rename 'y/A-Z/a-z/' {} \;

# Only files (not directories)
find . -type f -name "*.md" -exec perl-rename 's/-/_/g' {} \;

Advanced Techniques

Multiple Expressions

# Chain operations with -e
perl-rename -e 's/foo/bar/' -e 's/baz/qux/' *

# Or use semicolons
perl-rename 's/foo/bar/; s/baz/qux/' *

Conditional Rename

# Only if pattern matches
perl-rename 's/old/new/ if /pattern/' *

# Skip certain files
perl-rename 's/old/new/ unless /backup/' *

Using Perl Variables

# Counter for sequential naming
perl-rename 'our $n=1; s/^/sprintf("%03d_",$n++)/e' *.jpg

# Current date
perl-rename 'use POSIX; s/^/strftime("%Y%m%d_",localtime)/e' *

Lookahead/Lookbehind

# Replace only before extension
perl-rename 's/foo(?=\.\w+$)/bar/' *

# Replace only after prefix
perl-rename 's/(?<=prefix_)old/new/' *

Safety First

Always Dry-Run First

# Preview changes without executing
perl-rename -n 's/pattern/replacement/' *

# Verbose dry-run
perl-rename -nv 's/pattern/replacement/' *

Backup Strategy

# Create backup before rename
for f in *.txt; do cp "$f" "$f.bak"; done
perl-rename 's/old/new/' *.txt

# Or use git
git add . && git commit -m "Before rename"
perl-rename 's/old/new/' *

Comparison: perl-rename vs Others

TOOL            REGEX    BATCH    PREVIEW    PLATFORM
────────────────────────────────────────────────────────────────
perl-rename     Full     Yes      -n         Linux/Mac
rename (util)   Basic    Yes      No         Linux
mmv             Glob     Yes      Yes        Linux
zmv (zsh)       Full     Yes      -n         Zsh only
fd + sd         Full     Yes      --dry-run  Cross-platform

Troubleshooting

“Command not found”

# Check if installed
which perl-rename || which prename || which rename

# Arch: might be 'rename' not 'perl-rename'
pacman -Ql perl-rename

Escaping Special Characters

# Escape shell metacharacters
perl-rename 's/\[/(/g' *        # [ -> (
perl-rename 's/\$/dollar/g' *   # $ -> dollar
perl-rename "s/'//" *           # Remove apostrophes

Permission Denied

# Check file permissions
ls -la
# May need sudo for system files
sudo perl-rename 's/old/new/' /etc/files/*

Quick Reference Card

TASK                              COMMAND
────────────────────────────────────────────────────────────────
Preview changes                   perl-rename -n 's/X/Y/' *
Replace text                      perl-rename 's/old/new/' *
Replace all occurrences           perl-rename 's/old/new/g' *
Case insensitive                  perl-rename 's/old/new/i' *
Lowercase all                     perl-rename 'y/A-Z/a-z/' *
Remove spaces                     perl-rename 's/ /_/g' *
Change extension                  perl-rename 's/\.txt$/.md/' *
Zero-pad numbers                  perl-rename 's/(\d+)/sprintf("%03d",$1)/e' *
Add prefix                        perl-rename 's/^/prefix_/' *
Add suffix                        perl-rename 's/$/_suffix/' *
Swap parts                        perl-rename 's/(.+)-(.+)/$2-$1/' *
Remove pattern                    perl-rename 's/pattern//' *

See Also

  • man perlre - Perl regular expressions

  • man perlop - Perl operators (s///, y///)

  • BSH-004 - Text Processing (grep, sed, awk)

  • BSH-001 - Find Files and Directories