I have many files of different lengths but the same extension and I have tried many commands to rename all of them at once.

Is it possible to change only the last 10 characters of the base of all filenames? The 10 last characters are always the same.

For example :


I want to replace (12345678) with abcdefghij

  • Can you get more help , how to do this ? – 1001dlc Jul 14 '15 at 5:40
  • 2
    If you wanted to know how to do this, you should not just have asked whether it is possible. Give a few examples, by updating your post of file names before and after. Make sure it is clear if the 10 last characters on the original files are always the same or not. If they are not make sure to include what happens if the file name parts before them are different. And while you update your post change the question so the answer cannot be a simple Yes/No (which makes for a non-useful question for this site which is probably the cause for the down votes). – Anthon Jul 14 '15 at 5:58
  • 1
    did you want it to work for your exact example or for any combination of characters in the filename? The solutions below expect (12345678) to be in the filename for them to work (I think). – dakka Jul 14 '15 at 7:00
  • @dakka Good point. I've updated my answer. – Sparhawk Jul 14 '15 at 7:11

There are two Linux commands called rename that are commonly available in distributions. I prefer the perl-based rename, as it's more powerful. You can check which one you have using $ prename --version.

If you have the perl-based rename,

$ rename --version
perl-rename 1.9
$ rename 's/\(12345678\)/abcdefghij/' *.txt

If you want to check it first with a dry run, use the -n flag.

If you have the other rename,

$ rename --version
rename from util-linux 2.26.2
$ rename '(12345678)' abcdefghij *.txt

To remove the last 10 characters before .txt generally

If the characters are not always the same, you can use this in the general case.

For perl-based rename,

rename 's/.{10}\.txt\Z/abcdefghij.txt/' *.txt -n

For the other rename, I'm not sure if it's possible.

  • If you're globbing only .txt files, you can shorten the last pattern to .{10}\. and the last replacement to abcdefghij. – kos Jul 14 '15 at 7:13
  • @kos That won't work if there is another . in the filename, with at least ten characters preceding, e.g. foobarfoobar.foo(12345678).txt. However, I've just realised I need to anchor the txt too. I'll re-edit. – Sparhawk Jul 14 '15 at 7:15
  • Yeah, if that's a concern you'd rather not – kos Jul 14 '15 at 7:22
  • 1
    @kos I just figure that it's better to cover all edge cases, if it's not much more effort to code. – Sparhawk Jul 14 '15 at 7:25
  • It's probably better how you do it. In more complex cases I have the habit of just strictly covering the example tough, because covering every edge case would be way more extensive and, to be honest, those should be up to OP to be pointed out. However in this case I agree it was not much of an effort – kos Jul 14 '15 at 7:30

Try this. If happy with the proposed moves, remove the echo and rerun.

$ ls
download(12345678).txt  img(12345678).txt  upload(12345678).txt
$ for F in *; do echo mv "$F" "${F/(12345678)/abcdefghij}"; done
mv download(12345678).txt downloadabcdefghij.txt
mv img(12345678).txt imgabcdefghij.txt
mv upload(12345678).txt uploadabcdefghij.txt
  • nothing changed .. – 1001dlc Jul 14 '15 at 6:51
  • 1
    You should quote your variables, otherwise this would fail for files with whitespace in their name. – Sparhawk Jul 14 '15 at 6:55
  • i know this , it wouldn't fail .. – 1001dlc Jul 14 '15 at 6:58
  • respond As you've example but nothing changed finally – 1001dlc Jul 14 '15 at 6:59
  • 1
    @1001dlc please don't be so impatient. Did you try the for loop? Did you then remove the echo to run it for real, as instructed? If so, you are going to need to provide some feedback to help us understand why it didn't work for you – roaima Jul 14 '15 at 7:08

You can just do this in bash/dash/zsh, no need to revert to utilities that might not be installed. In bash:

for x in *"(12345678).txt"; do mv "$x" "${x%(12345678).txt}"abcdefghij.txt; done

the $x%pattern is for removing matchin suffices. From man bash:

          Remove matching suffix pattern.  The word is expanded to produce
          a pattern just as in pathname expansion.  If the pattern matches
          a  trailing portion of the expanded value of parameter, then the
          result of the expansion is the expanded value of parameter  with
          the  shortest  matching  pattern (the ``%'' case) or the longest
          matching pattern (the ``%%'' case) deleted.  If parameter  is  @
          or  *,  the  pattern  removal operation is applied to each posi‐
          tional parameter in turn, and the  expansion  is  the  resultant
          list.   If  parameter is an array variable subscripted with @ or
          *, the pattern removal operation is applied to  each  member  of
          the array in turn, and the expansion is the resultant list.


 ls |  awk '{printf "mv %s %s\n",$0,gsub("(12345678)","abcedfgh" );}' | bash
  • 1
    Probably find with -exec or -execdir is more robust than piping from ls. What about files with newlines in their name? Also, doesn't the awk part fail for files with whitespace in their name? – Sparhawk Jul 14 '15 at 6:57
  • there must be some kind of macros, every time someone pipe ls, another folk in U&L came and say "what about file with newline, pipe symbol, & and ; in their names ? " – Archemar Jul 14 '15 at 7:06
  • 1
    That's because piping ls is not a very robust concept. Why wouldn't you just use find? – Sparhawk Jul 14 '15 at 7:07
  • 1
    Indeed those are rare cases and maybe even 99% of the time it's safe to just parse ls, but maybe it's also worth a quick mention of the fact that such commands could break on such characters? – kos Jul 14 '15 at 7:08

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.