I need a command to recursively rename a large number of jpg files in Ubuntu.

However there are some problems. A normal group of files would look like ani-estate-villas_1431640729_3.jpg, ani-estate-villa_3627544278_7.jpg and ani-estate-villa_3143254376_5.jpg

I need to replace all - with _, remove all numbers and then add numbering which resets in every directory. So the same group of files should look like ani_estate_villas_1.jpg, ani_estate_villas_2.jpg, ani_estate_villas_3.jpg and the same with the other files in the other directories.

The depth of the recursion is 1 or 2 directories deep, so you might find a directory/file.jpg or directory/directory/file.jpg it's pretty much random.

Running a command in every directory with jpgs is also doable so if anyone has any idea on how to rename all files with those characteristics would be fine. Although running one single command is cooler, I'd much appreciate a bit more repetitive solution, because manually changing the 400+ jpg files is too much.

I tried using krename but it deletes my files.

  • It's certainly doable. Just to clarify, small question: ani-estate-villas_1431640729_3 should be reduced to ani_estate_villas_3 , or the last number should be somehow different based on other files? – Sergiy Kolodyazhnyy Jan 16 '17 at 23:32
  • Yep the last number must be a file numbering that starts over in every directory with jpg files. – Henry Ollarves Jan 16 '17 at 23:44
  • I edited my question to clarify your question. – Henry Ollarves Jan 16 '17 at 23:47
  • You mention file names that end with _ and a number, and file names that end with .jpg. Which is it? – Gilles 'SO- stop being evil' Jan 16 '17 at 23:57
  • They're all .jpg. Will edit to clarify – Henry Ollarves Jan 16 '17 at 23:58

You can use the prename command to rename files based on a transformation written in Perl.

Let's start simple. To rename all the .jpg files in a directory, changing all - to _, we can just use the s operator (we could also use tr). The Perl code is executed to transform each file name.

prename 's!-!_!g' *.jpg

To change the number sequence(s) at the end to a simple counter, we introduce a counter variable. I use the global variable $a as a counter (introducing extra variables is more complicated). The regular expression (\.[^/.]*)$ matches the file extension, and $1 in the replacement text stands for what the parenthesized group matched.

prename 's!-!_!g; ++$a; s!_[0-9_]+(\.[^/.]*)$!_$a$1!' *.jpg

Note that the files are renamed in the order given by the file name arguments, i.e. the order of expansion of *.jpg determines the numbering of the files.

Alternatively, we can initialize the counter explicitly with a BEGIN block.

prename 'BEGIN {$a = 1;} s!-!_!g; s!_[0-9_]+(\.[^/.]*)$!_$a$1!; ++$a;' *.jpg

To perform this in every subdirectory of the current directory, call find.

find -type d -exec sh -c 'cd "$1" && prename "$0" *.jpg' 's!-!_!g; ++$a; s!_[0-9_]+(\.[^/.]*)$!_$a$1!' {} \;
  • It's 2am here so I'm going to bed, but will give it a try first thing tomorrow. It seems it'll work, I really hope it does :). Thanks! – Henry Ollarves Jan 17 '17 at 0:49
  • I'm getting the following error: Global symbol "$c" requires explicit package name (did you forget to declare "my $c"?) at (eval 1) line 1. – Henry Ollarves Jan 17 '17 at 8:13
  • Sorry I forgot to tag you :) – Henry Ollarves Jan 17 '17 at 9:33
  • also, what version of perl are you using? Thanks! – Henry Ollarves Jan 17 '17 at 14:03
  • @HenryOllarves Oh, oops. Variables are local by default. Use $a, which owing to Perl's idiosyncrasies is always a global variable. – Gilles 'SO- stop being evil' Jan 17 '17 at 14:34

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.