Take the 2-minute tour ×

I am using Windows, and trying to use Cygwin to perform this task. I would like to rename the files and directories recursively as following:


I was thinking about using for loop, but for loop could not traverse the directories recursively. I can only use for and sed to rename a list of files in a directory:

for i in *; do j=`echo $i | sed 's/\(.\)\(..\)\(..\)\(.\)\(...\)\(.\)/\1-\2-\3-\4-\5-\6/g'`; mv $i $j; done

But I would like to rename several directories and the files within. So, I tried about "find", but I don't know how to use variables and regular expression with "find" command. Besides that, since I am using Cygwin, I can only use "mv" command instead of "rename" command. Thanks for any suggestions.

share|improve this question
rename(1) does not work the same as in Windows. Its syntax is rename PATTERN REPLACEMENT [files...]. –  amphetamachine Sep 4 '10 at 13:54
But the rename command is not found in Cygwin. So, I would like to use "mv" to rename the file. –  Allen Sep 4 '10 at 13:57

3 Answers 3

up vote 0 down vote accepted

Unix has several powerful ways to rename files. Here's one that uses zsh (make sure you have it installed). This first renames the directories, then renames the files in the directories.

autoload zmv
zmv -o -i '(?)(??)(??)(?)(???)(?)' '$1-$2-$3-$4-$5-$6'
zmv -o -i '(*)/(?)(??)(??)(?)(???)(?).(*)' '$1/$2-$3-$4-$5-$6-$7.$8'

It's not clear from your question whether the directories can nest. If they do, here's a single command that takes care of both directories and files, taking advantage of the fact that a single pattern replacement works for both:

zmv -o -i '(**/)(?)(??)(??)(?)(???)(*)' '$1$2-$3-$4-$5-$6-$7$8'

If you pass the -n option to zmv, it will show what the command would have done without actually moving the files. I use -o -i in my example so that it prompts for confirmation if it would overwrite a file and performs silently otherwise.

zmv is documented in the zshcontrib man page.

share|improve this answer
The command works. But is there any regular expression feature, for example if I want to extract the digits or words? –  Allen Sep 5 '10 at 13:34
@Allen: There are regular expressions in zsh, but not with the usual syntax: instead, you have to use shell patterns, documented (somewhat cryptically) in the zshexpn man page. I don't understand what you're after when you ask how to “extract the digits or words”. Maybe you could give a more specific example of what you want to do, perhaps as a separate question? –  Gilles Sep 5 '10 at 14:16
Thanks Giles, what I mean "extract the digits or words" are something like \d for digit character and \w for word character. –  Allen Sep 6 '10 at 2:51
@Allen: You can use character sets [0-9], [A-Z_a-z], [[:xdigit:]], etc like in usual regexps. Repetition is done with #: [0-9]# means 0 or more digits, [0-9]## means 1 or more digits. You can also write <7-42> to match any integer between 7 and 42 (with or without leading 0s). The full list is under “Filename generation” in the manual; extended_glob is automatically enabled in zmv. –  Gilles Sep 6 '10 at 7:17
@Giles: Thanks. your information is good. –  Allen Sep 7 '10 at 3:56

File::Rename or Debian's prename script, both in Perl.

share|improve this answer

This will find a bunch of files recursively and do a mv to rename them using sed to process the names. You can change the file specifications and add your sed command.

find . \( -name "1*.jpg" -o -name "1*.txt" \) -type f -exec sh -c mv "{}" "$(echo {} | sed '...')" \;
share|improve this answer
The above suggestion is failed. The result was: mv: .' and .' are the same file –  Allen Sep 5 '10 at 13:12
@Allen: I'm sorry, I should have put a -type f in it. I overlooked the fact that your directories are named similarly to your files. I'll edit my answer. I'm assuming that you replaced the "..." in the sed command with your actual sed command. –  Dennis Williamson Sep 5 '10 at 14:02
@Dennis: I got some error messages: "mv: missing file operand". I already replace the ... with the regular expression. Once I use: find . ( -name ".jpg" -o -name ".txt" ) -exec sh -c echo "{}" \; there will be nothing echo. If I remove the "sh -c", then the file names will be shown –  Allen Sep 6 '10 at 6:07
@Allen: Try single quotes around the shell command: find . \\( -name "*.jpg" -o -name "*.txt" \\) -exec sh -c 'echo "{}"' \; or find . \\( -name "*.jpg" -o -name "*.txt" \\) -exec sh -c 'mv "{}" "$(echo {} | sed '...')"' \; –  Dennis Williamson Sep 6 '10 at 6:47
@Dennis: The command you mentioned can work only for "echo". It cannot work when using "mv" –  Allen Sep 7 '10 at 4:06

Your Answer


