66

How can I bulk replace the prefix for many files?

I have a lot of files like

  • TestSRConnectionContext.h
  • TestSRConnectionContext.m

I would like to change all them to

  • CLConnectionContext.h
  • CLConnectionContext.m

How would I do this?

46
for name in TestSR*
do
    newname=CL"$(echo "$name" | cut -c7-)"
    mv "$name" "$newname"
done

This uses bash command substitution to remove the first 6 characters from the input filename via cut, prepends CL to the result, and stores that in $newname. Then it renames the old name to the new name. This is performed on every file.

cut -c7- specifies that only characters after index 7 should be returned from the input. 7- is a range starting at index 7 with no end; that is, until the end of the line.

Previously, I had used cut -b7-, but -c should be used instead to handle character encodings that could have multiple bytes per character, like UTF-8.

4
  • Thx, i got this right now by myself too. Marking as answer. Thx
    – ErikTJ
    Sep 6 '12 at 16:35
  • This works nicely, thanks. Can you explain what the -b7- does? Is this reference to the byte-list? ss64.com/bash/cut.html
    – imjared
    Sep 26 '13 at 16:01
  • @imjared Updated the answer with more details.
    – mrb
    Sep 26 '13 at 17:08
  • @mrb, how can I change this command to work for all folders and all files in the current directory? Apr 23 at 6:40
69

I'd say the simplest it to just use the rename command which is common on many Linux distributions. There are two common versions of this command so check its man page to find which one you have:

## rename from Perl (common in Debian systems -- Ubuntu, Mint, ...)
rename 's/^TestSR/CL/' *

## rename from util-linux-ng (common in Fedora systems, Red Hat, CentOS, ...)
rename TestSR CL *

If you want to use the version from util-linux-ng in a Debian system, it is available under the name rename.ul

3
  • 8
    A caveat: multiple versions of rename exist in the wild. Check your local rename documentation to figure out how to use yours.
    – jw013
    Sep 6 '12 at 17:39
  • 1
    To remove the alias do rename TestSR '' * Sep 21 '17 at 7:38
  • hmm... rename "\<pre\>" "" * -> Unterminated <> operator at (user-supplied code). Jul 25 '19 at 8:48
39

Shell parameter expansion is enough for simple transformations like this. Command substitution is less efficient because of the need to spawn extra processes (for the command substitution itself and the cut/sed).

for f in TestSR*; do mv "$f" "CL${f#TestSR}"; done
1
  • 2
    Explanation: TestSR* finds the files, CL${f#TestSR} will be the new name. The stuff after the # will be substituted from the filename (f).
    – Joe Eifert
    Jun 1 '18 at 11:31
4

Here's one way:

ls *.{h,m} | while read a; do n=CL$(echo $a | sed -e 's/^Test//'); mv $a $n; done
  • ls *.{h,m} --> Find all files with .h or .m extension
  • n=CL --> Add a CL prefix to the file name
  • sed -e 's/^Test//' --> Removes the Test prefix from the file name
  • mv $a $n --> Performs the rename
3

You can try with:

for i in TestSR*; do mv ${i} ${i/#TestSR/CL}; done

See man bash (section "Parameter Expansion") for details.

2

Well, it wasn't as hard as i though.

$ for f in TestSR*.m; do mv $f CL$(echo $f | cut -c7-); done;
$ for f in TestSR*.h; do mv $f CL$(echo $f | cut -c7-); done;
1
  • 2
    In case it helps for the future, you don't have to repeat the commands for your two patterns; you can use (for example): for f in TestSR*.[mh], for f in TestSR*.{m,h}, for f in TestSR*.m TestSR*.h.
    – mrb
    Sep 6 '12 at 22:37
1

If you need something more perlish you can do this

perl -e 'for(@ARGV) { rename($_, $n) if( ($n = $_ ) =~ s/^TestSR/CL/) }' *
0

I don't like any of the answers. My take is that you want a vanilla bash solution. So here you go!

Try this with echo first to see what is going to happen! Test your command before you use it on thousands of files!

Remove the './' is you want to put a prefix find . -type f -exec bash -c 'echo prefix_${0#./}' {} \;

Remove the extension if you want to put something after it find . -type f -exec bash -c 'echo ${0%.*}_suffix.${0##*.}' {} \;

Now to use this to rename just replace echo with mv $0

EXAMPLE: find . -type f -exec bash -c 'mv $0 1.${0#./}' {} \;

Inspired by: https://gist.github.com/larshaendler/723d2ec447c3c694b71dc6e3bc3aadc9

2
  • The way you wrote this, (nine years later:-), with find . ... {} \; you would be spawning separate bash subshells for each of the thousands of files you may find. That could make things very slow.
    – Chota
    Apr 3 at 10:36
  • @Chota That depends on the requirements. In my experience the usage of -exec has never been really slow on huge tasks. And yes it could be faster. The question was "how can I bulk rename with prefix for many files" and not how to bulk rename in the fastest most efficient way. I would say: if you want something for a bash script, then use the for loop method. If you want something you can type in from the top of your head to quickly operate in a terminal, learn the above structure. It's powerful and generic. Apr 6 at 5:54

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.