My directories are setup in this way:

  • dir 1
    • 001
      • 11-20-2001-RT SIMULATION-57976
    • 002
      • 11-20-2001-RT SIMULATION-30560
    • 003
      • 08-24-1998-RT SIMULATION-72882

and so on for about 250 entries. My goal is to move each of these subdirectories with the string RT SIMULATION to another directory, i.e. dir 2, but rename them to their respective parent directory. So I'm looking for.

  • dir 2
    • 001 (*this should correspond to 11-20-2001-RT SIMULATION-57976 in the above example)
    • 002
    • 003

So far I'm able to find these RT SIMULATION directories using this code for i in $(find /dir1/*/* -name "*RT SIMULATION*" -type d); echo "$i"; done;

Now I need to move and rename these directories to dir 2 based on their parent directory as specified above. Any help or pointers?

2 Answers 2


With zsh:

autoload -Uz zmv
zmv 'dir 1/(*)/*RT SIMULATION*(#q/)' 'dir 2/$1'

If you have to use bash, and assuming a GNU system, you could do something approaching with:

  shopt -s nullglob
  for dir in 'dir 1'/*/*'RT SIMULATION'*; do
    [[ -d $dir && ! -L $dir ]] || continue
    parent=${dir%/*}; parent=${parent##*/}
    mv -iT -- "$dir" "dir 2/$parent" || ret=$?
  exit "$ret"

BTW, see Why is looping over find's output bad practice? for what's wrong about your for i in $(find....


You can use find and the perl version of rename to do this. For example:

First, I'll set up a testing environment:

$ mkdir /tmp/goldenburrito
$ cd /tmp/goldenburrito
$ mkdir -p 'dir1/001/11-20-2001-RT SIMULATION-5797' \
    'dir1/002/11-20-2001-RT SIMULATION-30560' \
    'dir1/003/08-24-1998-RT SIMULATION-72882'
$ mkdir dir2

Then rename the "RT SIMULATION" sub-directories:

$ find dir1 -mindepth 2 -maxdepth 2 \
    -type d -name '*RT SIMULATION*' -print0 | 
        rename -0 -n 's:(/\d{3})/.*:$1:; s/^dir1/dir2/'
rename(dir1/003/08-24-1998-RT SIMULATION-72882, dir2/003)
rename(dir1/002/11-20-2001-RT SIMULATION-30560, dir2/002)
rename(dir1/001/11-20-2001-RT SIMULATION-5797, dir2/001)

The -mindepth 2 and -maxdepth 2 options used with find restrict the matches to only the second level directories beneath dir1. The NUL-separated output from find is piped into the rename script (which can take file & dir names as command-line args or from stdin).

For each matching directory name, the rename script first removes everything after the 3-digit directory name, then it changes "dir1" at the start of the directory name to "dir2".

Note that rename's -n option makes it a dry run, so it will only show what it would do without actually renaming any directories. Remove the -n, or replace it with -v for verbose output, when you've confirmed that it does what you want.

Also note: perl rename may be known as file-rename, perl-rename, prename, or just rename, depending on distro and/or how it was installed. On Debian, for example, it is called rename and is in the rename package (so, apt-get install rename).

It is not to be confused with the rename utility from util-linux which has completely different and incompatible capabilities and command-line options.

You can tell which version you have installed by running rename -V (if it mentions perl or File::Rename, it's the perl version).

Perl rename allows you to use any arbitrarily complex perl code to rename files, but is most often used to do simple sed-like s/search/replace/ operations on filenames.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .