5

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.

11
  • 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? Jan 16, 2017 at 23:32
  • Yep the last number must be a file numbering that starts over in every directory with jpg files. Jan 16, 2017 at 23:44
  • I edited my question to clarify your question. Jan 16, 2017 at 23:47
  • You mention file names that end with _ and a number, and file names that end with .jpg. Which is it? Jan 16, 2017 at 23:57
  • They're all .jpg. Will edit to clarify Jan 16, 2017 at 23:58

1 Answer 1

2

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!' {} \;
5
  • 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! Jan 17, 2017 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. Jan 17, 2017 at 8:13
  • Sorry I forgot to tag you :) Jan 17, 2017 at 9:33
  • also, what version of perl are you using? Thanks! Jan 17, 2017 at 14:03
  • @HenryOllarves Oh, oops. Variables are local by default. Use $a, which owing to Perl's idiosyncrasies is always a global variable. Jan 17, 2017 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.