Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This question already has an answer here:

I have a directory full of images:

DSCN4749.JPG
DSCN4750.JPG
DSCN4892.JPG
...

And I would like a one-liner to rename them to (say).

dscn4749.jpg
dscn4750.jpg
dscn4892.jpg
...

How do I do this?

Alternatives/extenstions/caveats

  • I want to recurse
  • The directory contains a mix of file types I only want to rename DSCN*.JPG files.
  • bash solution
  • perl solution
  • zsh solution
  • I want a new directory tree with hard links existing files.
  • I want to change name more than just a case change eg dscn5555.JPG to 05555.jpg

...

share|improve this question

marked as duplicate by Gilles, slm, jasonwryan, Renan, Anthon Feb 10 at 4:16

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
This is intended to be a canonical Q&A on this subject (see this meta discussion ), please feel free to edit my answer to improve it but if you solution is different then add your own below Stating extension/caveat/alternative method –  X Tian Feb 9 at 18:50
2  
Most of these (all?) are already present here: Batch renaming files –  terdon Feb 9 at 20:57
2  
-1 it would be better to edit the question terdon linked to than to re-ask it. –  virtualxtc Feb 9 at 22:32
    
@virtualxtc: Why is editing an ancient question better? Shouldn't the new question be formulated to ask about what has not been covered in the linked question? –  krlmlr Feb 9 at 23:25
1  
@krlmlr I wish I could find the meta thread on this for you as I'm sure I won't be as clear as it was: Whenever possible, you want to edit questions and answers so that this site has the best ones possible. However, if your edit would significantly change the intent of the question, then it is preferable to reference the original question (which also wasn't done) and ask a new one. –  virtualxtc Feb 10 at 8:41

7 Answers 7

With perl rename

rename 'y/A-Z/a-z/' *
share|improve this answer

POSIX sh for loop

for i in ./DSCN*JPG; do mv "$i" "$(echo "$i" | tr A-Z a-z)" ; done

bash while loop

good for unlimited number of files, reading a list of names from a file

Reading names from find command.

find . -maxdepth 1 -type f -name 'DSCN*JPG' | while IFS= read -r f; do
  mv -v "$f" "$( tr A-Z a-z <<< $f )"
done

Reading list of names in a file named flist

while IFS= read -r f; do mv -v "$f" "$( tr A-Z a-z <<<$f )"; done < flist
share|improve this answer
    
This is intended to be a canonical Q&A on this subject (see this meta discussion ), please feel free to edit my answer to improve it but if you solution is different then add your own below Stating extension/caveat/alternative method –  X Tian Feb 9 at 18:37
    
Why is the for loop good for only a limited number of files (esp. since a for loop doesn't suffer from a MAX_ARGS limitation)? –  kojiro Feb 10 at 0:52
    
Also, the while loop solution suffers from potential bugs when the listed files contain whitespace or start with a dash. –  kojiro Feb 10 at 0:58
    
@kijiro My mistake re for loop comment, will remove tks. –  X Tian Feb 10 at 1:11

Some linux distributions have a program called "mmv" (e.g. debian). This can perform a rename based on pattern matching of filenames. In your case, the command you'd want is:

mmv 'DSCN*.JPG' 'dscn#1.jpg'

It interprets the filename pattern itself, rather than relying on shell expansion, so remember to quote the wildcards. In the destination pattern, #1 refers to the first wildcard in the source pattern and so on. I'd suggest running

mmv -n 'DSCN*.JPG' 'dscn#1.jpg'

first, which will give a list of operations that will be performed as a dry run.

It can also handle recursively renaming, using the special ; pattern (which matches any number of subdirectory levels, similarly to the ** pattern used by some other tools). So to perform this operation recursively, the command is:

mmv ';DSCN*.jpg' '#1dscn#2.jpg'

It can also handle case transformation of the filenames itself, so if you weren't sure that all your files started with the DSCN prefix, for example, the following would work:

mmv '*.JPG' '#l1.jpg'

or even

mmv '*' '#l1'

or

mmv ';*' '#1#l2'

to perform the rename recursively.

A new directory tree with hard links to the original files can be produced using the -l option:

mmv -l ';DSCN*.JPG' '../output/#1dscn#2.jpg'

I haven't tested this, but I believe it will create directories as necessary.

share|improve this answer

recursive

easy recurse selecting DSCN*JPG files, and assumes no need to deal with newline in file names

find . -name "DSCN*.JPG" | while read f; do mv -v "$f" "$( tr A-Z a-z <<<$f )"; done

Safe, can deal with spaces, new lines, backslashes and anything else:

find . -name "DSCN*.JPG" | while IFS= read -r f; do 
   mv -v "$f" "$( tr A-Z a-z <<<$f )"; 
done
share|improve this answer

zsh

First load the zmv builtin with:

% autoload -U zmv

This can be run from the command line or put in .zshrc to always be enabled. To rename all of your files to lowercase, you simply use the command:

% zmv '*.JPG' '${(L)f}'

This will rename all files matching *.JPG to the same name but lowercase. This is one of the simplest use cases of zmv and it can do much more powerful batch renaming.

share|improve this answer

Generic pattern

As you can see from the answers, the generic pattern is

[Produce a set of file names to work on] | [read each name and run actionCommand]

actionCommand performs the desired action eg mv and generally takes two paramteres original file name and new file name.

producing filename

find is generally used.

To handle filenames with unusual characters the -print0 is used to terminate each string printed with the null character. However the reading sid of the pipe also needs to cooperate and read characters until null is read instead of terminating prematurely after a space.

reading each filename

Some commands can take a -0 option to handle the reading side of a null terminated character string.

The command xargs was designed for this purpose

bash has read -d\0

actionCommand

A general form cmd p1 p2 example mv oldfilename newfilename

producing the new filename

The new filename is usually derived from the original filename.

It can be as simple as appending a string, eg $oldname.New

  • tr is good for simple translation of characters
  • sed power editing of filenames

bash command substition

Example $( tr "{}" _ <<< $oldname )

command output substitution $( ) command that is run tr "{}" _ with input read from variable $oldname

share|improve this answer

change name with sed

for more complicated name changes/

find . -name DSCN\*.JPG | while read f; do 
   mv -v "$f" "$( sed -e 's/\([^0-9]*\)\([0-9]*\.\)\(JPG\)$/\2jpg/'  <<<$f )"; 
done
share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.