1

How can you bulk rename many files and/or directories by replacing a snippet f o o with b a r in the file/directory name?

For each suggested method, preferably answer the following questions.

  • Is it possible to preview the result of the command before doing the actual renaming? How?
  • Does the method work for prefixes only, for suffixes only, or does it work irrespectively?
  • Does the renaming affect only directories, only files, or both directories and files?
  • Will files/directories in sub-directories also be renamed?

Replacing a prefix, an example

To make the task a little more concrete, suppose that files like
o l d prefix file 1.c
o l d prefix file 1.h
o l d prefix file 2.c
o l d prefix file 2.h
should be renamed to
n e w prefix file 1.c
n e w prefix file 1.h
n e w prefix file 2.c
n e w prefix file 2.h

Suppose also that in the same directory there are (sub-)directories named
o l d prefix, dir 1 _
o l d prefix, dir 2 _

Will those directories be renamed as well?

Can you tweak your method to rename directories only (and not files)?
Or to rename files only (and not directories)?

Replacing a suffix

Also consider renaming a suffix in files so that
file 1, o l d suffix and file 2, o l d suffix are renamed to
file 1, n e w suffix and file 2, n e w suffix respectively.

And similarly for directories. Rename
dir 1., o l d suffix and dir 2., o l d suffix to
dir 1., n e w suffix and dir 2., n e w suffix respectively.

Recommended methods?

What method(s) of renaming would you recommend?

Note

Note that adding a prefix or a suffix to a name is just a special case of the more generic replacing of a prefix or a suffix, namely the case for which the original prefix or a suffix happens to be the empty string. Analogously, the case of removing a prefix or a suffix is also a special case of replacing a prefix or a suffix, namely the case for which the new prefix or a suffix is the empty string.

More issues to consider

I am aware that there are other and more advanced issues to consider when renaming files, such as adding or removing dates or sequence numbers and/or topics like in the last five questions among the references below.

I invite you to bring up any issue on renaming files/directories (or symbolic links) and to construct a suitable example in your answer.

When writing an answer, don't feel that you have to answer all the cases brought up here!
Feel free to focus on only one specific case (either one of the cases above, or some other case of your choice), if you prefer to do so.

References

5
  • 1
    Thanks for the suggestion. Maybe I wouldn't quite agree that my focus is on file/directory names containing spaces. I am just attempting to cover the general case. And since file names in general may contain spaces, I want to have example file names that contain spaces. Nevertheless I just changed the title to contain the word "spaces". If this is how others perceive my question, then why not?
    – Henke
    Feb 15 at 15:48
  • The bulkrename feature of ranger (need to install it) is probably the easiest way to do this task.
    – user492570
    Feb 15 at 15:52
  • bulkrename feature of ranger Interesting. I had never heard of it. Glad you tipped me. Thanks! :-) ~ * ~ Maybe not an obstacle, but I have to open vim to do that? (Not something I can do from the command-line ... ?) ~ * ~ Or maybe not? This link seems to say I can do it from the command line.
    – Henke
    Feb 15 at 16:01
  • You are right Henke about ranger using vim for this operation. This is because vim allows the user to highlight and replace columns of text. Well worth trying anyway.
    – user492570
    Feb 16 at 13:22
  • OK. Good to know. Thanks!
    – Henke
    Feb 16 at 15:08

1 Answer 1

3

0. Aiming for generic solutions 1

For the convenience of my future self and other readers, I will focus on generic solutions.

For simplicity I will assume that there are no quotation marks – no double quotes (") and no single quotes (') – in any file/directory name. 2

As a first example, I will show how to rename files with the pattern
o l d prefix file *.* to
n e w prefix file *.*,
thus renaming a prefix even if there are spaces in the file names.

I am also interested in renaming directories, and will therefore consider renaming the directories
o l d prefix, dir 1 _ and o l d prefix, dir 2 _ to
n e w prefix, dir 1 _ and n e w prefix, dir 2 _ respectively.

Secondly, I will show how to replace a suffix. As an example, the files
file 1, o l d suffix and file 2, o l d suffix are renamed to
file 1, n e w suffix and file 2, n e w suffix respectively.

Again, I want to see how this affects (or not affects) directories.
I will therefore also check to see whether the directories
dir 1., o l d suffix and dir 2., o l d suffix are renamed to
dir 1., n e w suffix and dir 2., n e w suffix respectively. 3

All of the above files and directories are available in a zip file:
http://user.it.uu.se/~hesc0353/Files-&-dirs-SEunix-A690768.zip. 4

Note.
The occurrence of echo in the solutions below means no renaming will take place.
This is an established technique to preview the renaming before you decide to go through with it.
Once the preview looks OK, just remove echo and run the command again to perform the actual renaming. 5

1. A generic solution using a for-loop

Renaming a prefix means replacing o l d prefix by n e w prefix : 6

for f in "o l d prefix"*; do\
 echo mv "$f" "n e w prefix""${f#o l d prefix}"; done

where I have chosen to search for files that start with o l d pref.

To rename a suffix, try :

for f in *"l d suffix"; do\
 echo mv "$f" "${f%o l d suffix}""n e w suffix"; done

Does the renaming affect only directories, only files, or both directories and files?

– This method changes the names of both files and directories.
If this is not what you want, try the find ... -type ... -exec method in the next section.

Will files/directories in sub-directories also be renamed?

– No. Using one of the above commands as a template will not affect files/directories in any sub-directories. You will have to purposely tweak the method quite a bit if you want to do that.
See for example the first solution in this answer.

2. A generic solution using find ... -exec mv

The find ... -exec mv method below gives you the option to rename files only or directories only – through the -type flag. It can also be tweaked to control how deep in the sub-directory tree the command should search for files or directories – through the -maxdepth flag.

Rename a prefix

The following command replaces o l d prefix by n e w prefix, but for directories only. Each file could be renamed in a separate sub-shell, but by having a for-loop inside -exec (and closing -exec with sh {} + instead of {} \;) the command runs more efficiently :

find . -maxdepth 1 -type d -name "o l d pr*" -exec sh -c\
 'for n; do echo mv "${n#./}" "n e w pre${n#./o l d pre}"; done' sh {} +

If you want to rename only files, simply use -type f instead of -type d (easy to remember: f for files, d for directories).

Rename a suffix

Similarly, here is how to replace a suffix in a bulk of files:

find . -maxdepth 1 -type f -name "*d suffix" -exec sh -c\
 'for n; do echo mv "$n" "${n%o l d suffix}n e w suffix"; done' sh {} +

Explanations

  • find . Search in the current directory and its sub-directories.
  • -maxdepth 1 Do not search in any of the sub-directories.
  • -type f Find files only (exclude directories).
  • -name "*d suffix" Search only files that end with d suffix.
  • -exec sh -c '...' Execute in sub-shells, allows command substitution, $(...).
  • -exec sh -c 'for n; do mv ...' sh {} + is more efficient than
    -exec sh -c 'mv ...' {} \; which otherwise does the same thing. 7
  • {} holds whatever find finds.
  • echo outputs the result of the command – when you are happy with the outcome,
    remove echo and run the command again.
  • mv "sou rce" "dest in" performs the actual renaming,
    replacing the old name sou rce with the new name dest in.
  • % See POSIX shells pattern filtering.
  • done ends the for-loop.
  • sh {} + As already indicated, sh {} + closes the -exec sh -c clause.

Rename both files and directories

To deliberately rename both files and directories in one go, just leave out -type :

find . -maxdepth 1 -name "o l d pr*" -exec sh -c\
 'for n; do echo mv "${n#./}" "n e w pre${n#./o l d pre}"; done' sh {} +

Will files/directories in sub-directories also be renamed?

The -maxdepth 1 clause ensures that no files/directories in the sub-directory tree will be affected.
If you deliberately want to rename a suffix for all files in all sub-directories, here is an example :

find . -type f -name "*d suffix" -exec sh -c\
 'for n; do echo mv "$n" "${n%o l d suffix}n e w suffix"; done' sh {} +

A word of warning.
This method will not work for renaming a prefix in many different sub-directories in one command.

3. A solution using Perl rename

This section is devoted to those of you who have Perl rename by Larry Wall installed on your system (or know how to install it). 8

I like the prudent practice of renaming the rename Perl-script to prename so as to avoid confusing it with the Linux rename.

Does the method work for prefixes only, for suffixes only, or does it work irrespectively?

The fact that you don't need to bother whether you are renaming a prefix or a suffix makes Perl rename easy to use.

For example, to replace o l d prefix with n e w prefix, do :

prename -n 's/o l d prefix/n e w prefix/' ./"o l d p"*

where the -n flag produces a preview.
Once the result is what you want, simply remove the -n flag and run the command again.

Does the renaming affect only directories, only files, or both directories and files?

As with the for-loop method of section 1, running prename will rename both directories and files.

However, you can choose to rename only files (exclude directories) by adding if -f at the end of the rename string, like so : 9

prename -n 's/o l d prefix/n e w prefix/ if -f' ./"o l d p"*

If you want to rename only directories (exclude files) use if !-f :

prename -n 's/o l d prefix/n e w prefix/ if !-f' ./"o l d p"*

Will files/directories in sub-directories also be renamed?

I have found that – when using forward slash (/) as delimiter – Perl rename alone will rename files/directories in the current working directory only and not in any of the sub-directories.
If you use some other character as delimiter, you can actually use prename to rename files/directories in the sub-directory tree.
The second solution of this answer is an example of such a rather unorthodox practice.

A more normal practice would be to combine find ... -execdir with prename.
For such an example, see this answer.

4. Other good alternatives for renaming files or directories

In case you don't like any of the above methods, consider using sed or awk (possibly in combination with xargs).

References


1 When testing the commands/solutions provided in this answer, I have neither used genuine Linux nor genuine Unix, but MSYS2 on Windows 10, which can be described as an emulated arch-Linux running on Microsoft Windows. Of course, a viable alternative for Windows users like myself would be to use Windows Subsystem for Linux (WSL).
I use MSYS2 because I find it convenient and easy to use.

2 If in doubt, before considering any renaming whatsoever, check the results of
the commands ls *\"* and ls *\'*.
Or better still: find . -name '*"*' and find . -name "*'*".
To have quotation mark(s) in file/directory names is definitely to ask for trouble, I think.
This answer lists what characters are forbidden in file/directory names.
– For Linux/Unix, there is only one forbidden character: forward slash (/).

3 I will not aim for a solution that changes both a prefix and a suffix in one go, as asked for in the question Renaming files with Bash, removing prefix and suffix. (If you need to rename both a prefix and a suffix, I would suggest replacing one of them in one command, and then replace the other one in another command.)

4 I encourage the reader to download and unzip the zip file to some (empty) directory, and then try out all the commands I provide in this answer.

5 For files and directories containing spaces, the preview may look wrong because it is missing the surrounding double-quotes ("). Removing echo will still make the command run correctly.
(Don't take the preview too literally!)

6 I use a backslash (\) to line-break long commands so that you as a reader won't need to scroll horizontally. When you construct a concrete example yourself, I recommend removing the backslash and writing the whole command in just one line.

7 To understand more about the difference between {} + and {} \;, see for example How to terminate the shell commands invoked by -exec (and its references).

8 Try typing rename or prename in your terminal (and hit Enter). If Perl rename is installed, expect to see Usage: rename [-v] [-n] [-f] perlexpr [filenames] or something similar – where the word perlexpr is included.
If it is not installed, expect to see something like bash: prename: command not found.
Another thing you could try is which prename.

9 This comment says the if -f clause will also rename symbolic links.
It suggests using if (-f && ! -l) instead, if symlinks are not to be renamed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.