How to use cygwin (or linux command) to rename the files and directories recursively with regular expression

2

1

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:
From:
1010110010\
1010110010\1010110010.jpg
1010110010\1010110010.txt
1010110020\
1010110020\1010110020.jpg
1010110020\1010110020.txt
...

to:
1-01-01-1-001-0\
1-01-01-1-001-0\1-01-01-1-001-0.jpg
1-01-01-1-001-0\1-01-01-1-001-0.txt
1-01-01-1-002-0\
1-01-01-1-002-0\1-01-01-1-002-0.jpg
1-01-01-1-002-0\1-01-01-1-002-0.txt
...

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.

Allen

Posted 2010-09-04T13:36:05.300

Reputation: 399

rename(1) does not work the same as in Windows. Its syntax is rename PATTERN REPLACEMENT [files...]. – amphetamachine – 2010-09-04T13:54:27.573

But the rename command is not found in Cygwin. So, I would like to use "mv" to rename the file. – Allen – 2010-09-04T13:57:14.987

Answers

0

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.

Gilles 'SO- stop being evil'

Posted 2010-09-04T13:36:05.300

Reputation: 58 319

The command works. But is there any regular expression feature, for example if I want to extract the digits or words? – Allen – 2010-09-05T13:34:19.950

@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 'SO- stop being evil' – 2010-09-05T14:16:50.943

Thanks Giles, what I mean "extract the digits or words" are something like \d for digit character and \w for word character. – Allen – 2010-09-06T02:51:47.047

@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 'SO- stop being evil' – 2010-09-06T07:17:30.227

0

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 '...')" \;

Paused until further notice.

Posted 2010-09-04T13:36:05.300

Reputation: 86 075

The above suggestion is failed. The result was: mv: .' and.' are the same file – Allen – 2010-09-05T13:12:25.133

@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. – Paused until further notice. – 2010-09-05T14:02:09.480

@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 – 2010-09-06T06:07:53.433

@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 '...')"' \; – Paused until further notice. – 2010-09-06T06:47:40.223

@Dennis: The command you mentioned can work only for "echo". It cannot work when using "mv" – Allen – 2010-09-07T04:06:01.193

@Allen: Why not? It worked when I tested it. – Paused until further notice. – 2010-09-07T06:44:37.203

@Dennis: I not sure why I cannot work with "mv". I think because 'mv "{}" "$(echo {} | sed ' is assumed as a string, then the regular expression is assumed as the command, and finally '...')"' is another string. – Allen – 2010-09-08T03:04:11.470

@Allen: Do you get an error message? What is it? – Paused until further notice. – 2010-09-08T03:59:39.913

Dennis: Error message: $ find . ( -name ".jpg" -o -name ".txt" ) -exec sh -c 'mv "{}" "$(echo {} | sed 's/([0-9])([0-9][0-9])([0-9][0-9])([0-9])([0-9][0-9][0-9])([0-9 ])/\1.\2.\3.\4.\6.0\5/g')"' ; sh: command substitution: line 0: syntax error near unexpected token (' sh: command substitution: line 0:echo ./1010110010/1010110010.jpg | sed s/([0- 9])([0-9][0-9])([0-9][0-9])([0-9])([0-9][0-9][0-9])([0-9])/1.2.3.4.6.05/g' mv: cannot move ./1010110010/1010110010.jpg' to': No such file or directory – Allen – 2010-09-10T06:15:05.903

Dennis: Thanks for your help. I think the "find" command really cannot help to solve my problem recursively. Because -type f will not work correctly since my directory name and the filename have the same pattern. – Allen – 2010-09-12T07:42:05.060

0

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

user1686

Posted 2010-09-04T13:36:05.300

Reputation: 283 655