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
-
NVIDIA Released Driver for Upcoming NVIDIA 560 GPU for Linux
Not only has NVIDIA released the driver for its upcoming CPU series, it's the first release that defaults to using open-source GPU kernel modules.
-
OpenMandriva Lx 24.07 Released
If you’re into rolling release Linux distributions, OpenMandriva ROME has a new snapshot with a new kernel.
-
Kernel 6.10 Available for General Usage
Linus Torvalds has released the 6.10 kernel and it includes significant performance increases for Intel Core hybrid systems and more.
-
TUXEDO Computers Releases InfinityBook Pro 14 Gen9 Laptop
Sporting either AMD or Intel CPUs, the TUXEDO InfinityBook Pro 14 is an extremely compact, lightweight, sturdy powerhouse.
-
Google Extends Support for Linux Kernels Used for Android
Because the LTS Linux kernel releases are so important to Android, Google has decided to extend the support period beyond that offered by the kernel development team.
-
Linux Mint 22 Stable Delayed
If you're anxious about getting your hands on the stable release of Linux Mint 22, it looks as if you're going to have to wait a bit longer.
-
Nitrux 3.5.1 Available for Install
The latest version of the immutable, systemd-free distribution includes an updated kernel and NVIDIA driver.
-
Debian 12.6 Released with Plenty of Bug Fixes and Updates
The sixth update to Debian "Bookworm" is all about security mitigations and making adjustments for some "serious problems."
-
Canonical Offers 12-Year LTS for Open Source Docker Images
Canonical is expanding its LTS offering to reach beyond the DEB packages with a new distro-less Docker image.
-
Plasma Desktop 6.1 Released with Several Enhancements
If you're a fan of Plasma Desktop, you should be excited about this new point release.