-1

I'm trying to rename all files in a directory from having the .JPG ext to .jpg but it isn't working.

I have looked around the net and found a few things but I can't seem to get any to work. The latest one I tried was:

rename -n .JPG .jpg *.JPG

I used the -n flag to see what would be modified but I got no response (no files).

What am I doing wrong here!?

Brett
  • 19,449
  • 54
  • 157
  • 290
  • rename is a perl program that will not be installed by default. I usually use a combination of find, mv, echo, and sed for this kind of thing. – John Powell Jun 11 '14 at 07:45
  • http://stackoverflow.com/questions/13051871/change-filenames-to-lowercase-in-ubuntu-in-all-subdirectories should help – John Powell Jun 11 '14 at 07:46
  • Try rename -n JPG jpg *.JPG or rename 's/\.JPG$/.jpg/' *.JPG – bedna Jun 11 '14 at 07:55
  • @JohnBarça Semitrue, there are actually two implementations of `rename` and not all systems ship with the way more useful `perl` version. – Adrian Frühwirth Jun 11 '14 at 08:27
  • @AdrianFrühwirth. Thanks for the clarification. I am afraid of perl, though when I look at the linux one liners I write to get round that fear, maybe I shouldn't be :D – John Powell Jun 11 '14 at 08:31
  • @JohnBarça Heh, I hear you. I usually just resort to a simple shell loop with globbing myself, but `perl` `rename` can be *extremely* useful when paired with `s///e` (see for example my answer [here](http://stackoverflow.com/a/23359228/612462)), so I feel it does deserve a little more attention. `zsh` users have `zmv`, but `rename 's///e'` seems more powerful to me. – Adrian Frühwirth Jun 11 '14 at 08:37
  • @AdrianFrühwirth. Thanks, I'll have another look. I have had to rename millions of files on occasion. – John Powell Jun 11 '14 at 08:42

2 Answers2

4

If you don't want to use rename, you mention you have tried various things, then with only built-in bash utils, you can do this.

for x in `find . -maxdepth 1 -type f -name "*.JPG"` ; do mv "$x" `echo $x|sed 's/JPG/jpg/g'`; done

The backticks around find run the expression and assign the result to variable x. There are various switches you can use with find to limit by time, size, etc, if you need more sophisticated searching than just all JPG in current directory, for example. Maxdepth 1 will limit the search to current directory.

EDIT:

As pointed out by Adrian, using sed is unecessary and wasteful as it uses another subshell, so instead, this could all be compressed to:

 for x in `find . -maxdepth 1 -type f -name "*.JPG"` ; do mv "$x" "${x%.JPG}.jpg"; done
John Powell
  • 12,253
  • 6
  • 59
  • 67
  • As I stated in a comment to my answer, [for foo in $(find) should be avoided](http://mywiki.wooledge.org/ParsingLs) and the `sed`construct is not needed either (you could e.g. do `mv "$x" "${x%.JPG}.jpg"` which avoids two subshells (faster) and is shorter. Also, don't forget to quote your variables otherwise they will be subject to globbing and word splitting which means that certain filenames will completely break your command. – Adrian Frühwirth Jun 11 '14 at 08:50
  • @AdrianFrühwirth. OK, left in find as I like its flexibility, but made the rest of the edits you suggested. Thanks again. – John Powell Jun 11 '14 at 10:22
3

The proper perl rename expects a regular expression so you would achieve this doing:

$ rename 's#\.JPG$#.jpg#' *.JPG

The shitty util-linux version of rename does not have an -n switch so you would have to do:

$ rename .JPG .jpg *.JPG

Consult the man page to check which implementation is actually installed on your system.

Adrian Frühwirth
  • 42,970
  • 10
  • 60
  • 71
  • As a matter of interest, how do you think rename compares with using the find approach, in terms of available switches like size, time, depth, etc? – John Powell Jun 11 '14 at 08:35
  • @JohnBarça `rename` has no recursive mode, which is probably the most important scenario where it doesn't prove so useful on its own (but given the whole script is just a few LOC I guess one could add this quite easily). Of course, if you require to limit the results in a way `find` is absolutely the right tool, but **don't** do `for f in $(find ...)` (see [here](http://mywiki.wooledge.org/ParsingLs) why). Then again, nothing stops you from combining both. – Adrian Frühwirth Jun 11 '14 at 08:44