Bulk renaming files with the rename command
Combining Multiple Operations
As shown in Figure 3, the preceding example only reformatted the dates. I still need to insert the colons between each time component. Again, I can use back references, as follows:
rename 's/([0-9]{2})([0-9]{2})([0-9]{2})$/$1:$2:$3/' *
This command certainly works, but what if I want to use one single rename
command to do both the date and time manipulation instead of running two separate rename
commands in sequence? Certainly, I could combine the two search expressions into one very long search expression, but this quickly becomes cumbersome and very difficult to read:
rename 's/([0-9]{4})([0-9]{2})([0-9]{2})_([0-9]{2})([0-9]{2})([0-9]{2})$/$3-$2-$1_$4:$5:$6/' *
Fortunately, it is possible to perform both tasks using one command but keep the tasks logically separated. If each expression is separated by a semicolon character, rename
can execute two or more expressions in one command:
rename 's/([0-9]{4})([0-9]{2})([0-9]{2})/$3-$2-$1/; s/([0-9]{2})([0-9]{2})([0-9]{2})$/$1:$2:$3/' *
(Note the new line after the semicolon character. While not necessary, it improves the readability of the search expression; rename
interprets it as a harmless whitespace character).
Transliterating Characters
The y///
command transliterates text. It looks for each character specified in the command's first parameter and replaces any instance of that character with the corresponding character in the second parameter. For example, to replace any A
s with Z
s and any Z
s with A
s in file names, use:
rename 'y/AZ/ZA/' *
After executing this command, the file ZAGREB.TXT
becomes AZGREB.TXT
.
While the y///
command is case-sensitive like s///
, the y///
command does not have an option switch to enable case-insensitivity (see the "s/// Options" box for more information). Thus, the above y///
command will replace ZAGREB.TXT
but not zagreb.txt
. Furthermore, it will change Zagreb.txt
to Aagreb.txt
, but not to Azgreb.txt
as you may expect. To do that, you would need to change the command to:
rename 'y/AZaz/ZAza/' *
One common use of y///
is to convert uppercase file names to lowercase, or vice versa, which is useful for old MS-DOS or early Windows files that saved files in all uppercase characters. You can implement such transliteration by specifying the entire alphabet in the command explicitly, but doing so is cumbersome because that would require typing out at least 52 letters: the 26 uppercase letters in the search expression, and the 26 lowercase letters in the replacement expression. Instead, you can specify ranges of characters in the search expression, as in y/[A-Z]/[a-z]/
(to replace uppercase characters with their lowercase equivalents).
Like the s///
command, the y///
command accepts one or more options following the final slash of the command. None of these options are likely to be useful for general purposes, but c
and d
might have some niche uses (see the "y/// Options" box).
y/// Options
Like the s///
command, the y///
command accepts a few option characters; each option alters the behavior of the y///
command in its own way. The y///
options are rarely useful, but two options, c
and d
, might come in handy.
Both of these options are used in connection with an intrinsic behavior of y///
known as squashing: If the number of characters on the replacement list is less than the number of characters on the search list, the last character on the replacement list is duplicated until the search and replacement lists are equal in length. For example,
y/[A-Z]/x/
is equivalent to:
y/[A-Z]/xxxxxxxxxxxxxxxxxxxxxxxxxx/
Both expressions will replace any uppercase letter with a lowercase x character. The first, however, is much more compact and easier to read.
One potentially useful option, c
, instructs y///
to complement the list of characters on the search list and replace any character that is not present on the list. When combined with squashing, this can be used to change forbidden characters not explicitly on the search list to one particular placeholder character. For instance, if you have files with unprintable characters in their names (*nix/Linux filesystems can handle most non-printable characters in file names), you can quickly clean up the file names by replacing all non-alphabetic, non-numeric, non-underscore/hyphen characters in the file names with dot (.) characters, as in:
y/[A-Z][a-z][0-9]_-/./c
Another potentially useful option, d
, disables squashing and deletes any character on the end of the replacement list that has no corresponding character on the search list. Thus, y/_.[A-Z]/_.[a-d]/d
will convert the file name DOC_1993.BAK into dc_.ba. While this example is contrived, it is the nature of an option switch with limited practical utility.
Moving Files Between Directories
Another potential use of rename
is to have each category of logfile placed in its own directory. In Listing 4, I have several dated logfiles named daemon
, syslog
, and messages
. While I currently only have five logfiles in that directory, I could eventually end up with hundreds or even thousands of logfiles to manage. Consequently, I want to move each type of logfile into its own directory (e.g., I want syslog_13-10-2019_23:36:11
to be moved into a directory called syslog
). Ideally, I would also like the initial part of the logfile's name to be removed because the containing directory's name should make clear the type of logfile. Listing 5 shows the desired resulting directory tree.
Listing 5
Separating into Subdirectories by Name
$ ls -FNR .: daemon/ messages/ syslog/ ./daemon: 09-03-2020_07:18:42 ./messages: 02-04-2023_09:32:00 13-12-2021_13:43:27 ./syslog: 13-10-2019_23:36:11 26-07-2022_18:56:03
Fortunately, rename
can move files just as easily as it can rename them. In fact, it can do both in the same step. Obviously, I want to do both simultaneously in this case, because I want to move the file and then remove the first part of the file name.
Unfortunately, to move a file to another directory, rename
requires that the destination directory already exist; rename
will not create the directory for you. Prior to running rename
, you will have to pre-create all the necessary directories. I used the following shell one-liner to create the directories before running rename
:
find . -maxdepth 1 -type f -printf '%f\0' | grep -Eoz '^[^_]+' |xargs -0 mkdir
This one-liner lists all files immediately under the current directory – not any files under subdirectories – and then takes the part of the file name up to the first underscore (e.g., messages
), and creates a new directory in the current directory named after the first part of the file name.
Now, to move each logfile and then remove the initial part of each file name, I use:
rename 's/^([^_]+)_/$1\//' *
There are several things to note here. The first is that I instructed rename
to search for any length of string at the very beginning of the file name that does not contain an underscore (the ^([^_]+)
in the search expression). This takes advantage of the fact that the logfile type is separated from the date by an underscore. I then use a back reference followed by a slash in the replacement expression to tell rename
to move the file into a directory named after whatever was matched by the aforementioned parenthesized expression.
Note how I escaped the slash character (as in \/
) to guarantee that rename
does not mistake the slash as the end of the replacement expression. Remember, the search and replacement expressions, as well as any options to the s///
command, are separated by slash characters, just like file-name components are separated by slashes. Actually, I could have used virtually any character to separate the parts of the s///
command; while using slashes is the common convention, I also could have used at signs (@
) in the rename
command above, or in any of the previous s///
commands. The following would have worked just as well:
rename 's@^([^_]+)_@$1/@' *
By using a character other than the slash to separate the parts of the s///
command, I no longer have to escape the slash in the replacement expression that denotes part of a directory path. In my opinion, this makes the command a bit easier to read. Just make sure that the character that you choose appears neither in the search or replacement expression (or is escaped where it appears).
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.