8

This is a mess. How do I know which command to use when we expect Perl's rename with s/// sed-like syntax, when there're tons of different implementations of rename, that are different versions of the Perl one or most of the time rename.ul (binary)?

muru
  • 72,889

1 Answers1

13

Perl's rename

The most well-known and intuitive tool for bulk renaming files is Perl's rename. It is pretty much like sed on steroids (but meant for renaming files).

TL;DR

If you want to use it the expected way, better use Perl's CPAN to install the expected version. There's too many versions out there.

See "Generic Perl CPAN install" below.

Usage (sed s/// like)

It's able to do powerful regex processing:

rename [options] 's/<regex>/<replacement>/[modifiers]' <FILE(S)>[*]
<STDIN> | rename [options] 's/<regex>/<replacement>/[modifiers]'

Examples

  • If you want to add spaces between each word of an mp4 filename in TitleCase (PascalCase to Words Separated By Spaces):

    rename -n 's/\B[[:upper:]]/ $&/g' ./*.mp4
    rename(./FooBarBaz.mp4, ./Foo Bar Baz.mp4)
    

    Remove -n switch, aka dry-run when your attempts are satisfactory to rename for real.

  • you even can inject calls in the replacement part, like sprintf "%03d", 7 zero padding with the e modifier:

    $ touch {1..3}.txt
    $ rename -n 's/(\d+)\.txt/sprintf "%03d", $1/e' ./*.txt
    rename(1.txt, 001.txt)
    rename(2.txt, 002.txt)
    rename(3.txt, 003.txt)
    
  • reverse order of text separated by - using capture group:

    $ rename -n 's/(\w+)-(\w+)-(\w+)/$3-$2-$1/' ./foo-bar-base.txt
    rename(foo-bar-base.txt, base-bar-foo.txt)
    

    or using Perlish way (TMTOWTDI):

    $ rename -n 's/(\w+)-(\w+)-(\w+)  # capture groups
                  /join "-", reverse @{^CAPTURE}/xe' foo-bar-base.txt
    rename(foo-bar-base.txt, base-bar-foo.txt)
    

You (Wo|Do)n’t Learn Perl in Five Minutes

Getting to grips with Perl is time well spent. But to start using the time-saving capabilities of the rename command, you don’t need to have much Perl knowledge at all to reap large benefits in power, simplicity and time.

Check your own version

note There's another binary tool with the same name used on some distro. Depending on your distro, the Perl version can be called perl-rename, file-rename, prename, pname or rename.
There's also a Python rename command out there !

rename --version

should look like this:

/usr/bin/rename using File::Rename version 1.30, File::Rename::Options version 1.10

or on old versions:

Unknown option: help
Usage: rename [-v] [-n] [-f] perlexpr [filenames

Or

rename 2>&1 | grep -i perl
    [ -e|-E perlexpr]*|perlexpr [ files ]

And not something using rename from util-linux

Table of default versions VS distros of rename command

Borrowed from this comment on tldr-pages's GitHub issue tracker by @mebeim:

Perl (old) Perl (new) Perl (other?) C
Linux (Debian) prename (pkg perl), deprecated file‑rename (pkg rename) N/A rename.ul (pkg util-linux)
Linux (Ubuntu) N/A file‑rename (pkg rename) N/A rename.ul (pkg util-linux)
Linux (Arch) N/A N/A perl‑rename (pkg perl-rename) rename (pkg util-linux)
Linux (CentOS, RHEL) N/A N/A N/A rename (pkg util-linux)
Linux (Fedora) N/A N/A prename (pkg prename) rename (pkg util-linux)
Linux (openSUSE) N/A N/A N/A rename (pkg util-linux)
macOS (Homebrew) N/A N/A rename (pkg rename) rename (pkg util-linux)
Windows N/A N/A N/A N/A
Solaris N/A N/A N/A N/A

Important notes:

  • on Windows, rename is a completely different command (therefore I did not list it above), but can be used as well, check how to use Perl's rename on windows

  • on Solaris, no rename command exists

  • on macOS, the Homebrew packages rename and util-linux conflict

  • on macOS, the Homebrew package rename offers a Perl script that looks different from the others

  • on Arch Linux, the perl-rename package offers a Perl script that's also different from the others

  • on Feroda, the prename offers a Perl script that's also different from the others

  • on Debian, prename and file-rename are alternatives for rename

  • on Ubuntu, file-rename is the only alternative for rename

  • mksh has a builtin rename. To use Perl's rename, it is necessary to either use full path: /usr/bin/rename, or define an alias rename=/usr/bin/rename

Generic Perl CPAN install with or without root privileges

I recommend this way, since there're too many different versions around. This way, you know exactly which version you will have.

  • use cpan -i File::Rename (Better use perl brew for regular user). The rename command will be available. If not, your PATH does not include Perl script utilities.
  • for Debian*, use dh-make-perl --build --cpan File::Rename to make a Debian package

If you can't install anything, download it as a standalone script (simplified old version with no dependencies (except perl) and less switches than the newer versions)

Mapping rename VS distros if not the good one

If you prefer your system package manager:

This is the default rename command on Debian (alternative) like OS (unlike Arch Linux, rpm-based distros, Slackware and *BSD).

  • rpm-based distros:

    dnf install prename
    
  • Arch Linux/Manjaro:

    pacman -S perl-rename
    
  • Gentoo:

    emerge dev-perl/rename
    
  • NixOs:

    nix-env -i perl5.36.0-rename
    nix-env -iA nixos.perlRename
    

This is not the recommended way for purists.

  • *BSD:

    pkg install p5-File-Rename
    
  • Alpine Linux (in branch edge of the testing repository, not used by default):

    apk add perl-file-rename --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/
    
  • macOS:

    brew install rename
    
  • Debian-like/Ubuntu:

    apt install rename
    
  • Slackware: slackbuild

Documentation

Unicode

There's also a specific Unicode rename implementation: Unicode::Tussle

If you have file with contiguous Unicode UTF8 characters like AaaÃééZzz.mp4 the Unicode part will be ignored. One solution is to use the special switch for unicode:

-u, --unicode [encoding]

Treat filenames as perl (unicode) strings when running the user-supplied code.

Decode/encode filenames using encoding, if present.

encoding is optional: if omitted, the next argument should be an option starting with '-', for instance -e.

or if you have a (older) version without -u, you can do:

PERL_UNICODE=ASD rename -n 's/\B\p{Lu}/ $&/g' ./*.mp4

Check

perldoc perlrun | less +/PERL_UNICODE

Security

To avoid possible shell injection (thanks @Stephane Chazelas):

rename -n 's/.*//' '--e=system"uname"#.mp4'
Linux

Make it a habit to use: (the most portable)

 rename -n 's/.*//' ./*

or if supported:

rename -n 's/.*//' -- *

It will both prevent shell injection and treating files starting with - as a switch.
Try to rename a file like rename -n 's/.*//' -foobar.txt

Vilinkameni
  • 781
  • 1
  • 4
  • 12
  • 1
    (Coming from https://unix.stackexchange.com/a/757503/367454). In Alpine Linux, there is a package perl-file-rename, but it is in the testing repository of edge branch and isn't installed by default. Furthermore, mksh has rename as a builtin. Quoting man mksh: rename [--] from to (defer always, needs rename(2)) Renames the file from to to. Both pathnames must be on the same device. Intended for emergency situations (where /bin/mv becomes unusable); thin syscall wrapper. – Vilinkameni Sep 26 '23 at 21:27