Take the 2-minute tour ×

I used to do this with Hazel. I'd move everything from ~/Downloads/ to ~/Downloads/Archive/Pictures, Documents, Videos etc. based on the file extension, and when a file with an identical name already existed, Hazel would just append a number to the file it was moving.

I wanted to write a shell script that would achive this but I quickly realized I have no idea how to rename the files without any user input. The scheme to rename by could be a simple counter after the filename and it should only take place when mv would otherwise overwrite the existing file. It should also be able to continue the counter should there already have been numerous instances with an identical filename. So, if I were moving dirA/file.ext to dirB/ that already has file.ext and file2.ext in it, the script should start counting at 3 and rename dirA/file.ext to dirB/file3.ext.

Can anyone offer any guidance on how to go about achieving this? Preferably with a shell script but if not, then either in Ruby, Perl, or Python. Just knowing whether this is even possible with a shell script would help me.

share|improve this question
Sorry for stating the obvious, but why is Hazel no longer an option? –  John T Jul 22 '11 at 17:49
I don't have a license for it, I want to do this on all my boxes and two of them run Debian, and I want to know how to do it myself. –  Jukka Haav Jul 22 '11 at 17:56
add comment

2 Answers

You can also do it with a single command if you have the GNU version of mv installed on each workstation. The default shipped with Mac OS X does not support the --backup switch. You can obtain the GNU Coreutils for Mac OS X through Macports and many other locations.

Then it's just a matter of:

mv --backup=numbered dirA/file.ext dirB/

The resulting filename will be file.ext.~1~, file.ext.~2~ and so on.

enter image description here

share|improve this answer
Thanks. Got it through Homebrew. –  Jukka Haav Jul 22 '11 at 20:40
add comment

It's not that hard. If the destination file exists, you just need to break the file apart into the basename and the extension, and increment a counter until the new filename does not exist in the target directory.


file=$(basename file.ext)

if [[ ! -e "$dest_dir/$basename.$ext" ]]; then
    # file does not exist in the destination directory
    mv "$source" "$dest_dir"
    while [[ -e "$dest_dir/$basename$num.$ext" ]]; do
        (( num++ ))
    mv "$source" "$dest_dir/$basename$num.$ext" 
share|improve this answer
Does exactly what I had in mind. Thank you! –  Jukka Haav Jul 22 '11 at 20:38
add comment

Your Answer


