Rename files/directories based on their name

i have hundreds of directories that have to be renamed. the directory structure is fairly uniform which makes the scripting a little simpler.

suppose i have many directories like this */*/*/*abc* (in other words i have similar directory names 3 dirs deep that all contain the pattern abc in their dir name). i would like to rename any directory that contains the pattern *abc* to, say, xyz (or anything really, but not just change the abc part. i want to change the entire dir name with xyz).

there are several pattern variations that i would like to rename, so i'm trying to develop a script for which additions would be easy.

i'm using Unix (Solaris) with tcsh, and my work so far (i'm real green to scripting so there may be some mistakes) is:
.............................

foreach old ( abc )
set new=`echo $old | sed 's/abc/xyz'`
mv $old $new
end

.............................

this works for dirs with the exact name abc (and that's cool), but when i try:

.............................

foreach old ( *abc* )
set new=`echo $old | sed 's/*abc*/xyz'`
mv $old $new
end

.............................

it fails, saying mv: blahblah is a directory (or something to that effect)

i think that covers it all. if anyone wants to help but needs more info just ask.

thanks in advance for your help

quant

I don't think I'm understanding completely what you want to do. If you have hundreds of directories all with "abc" somewhere in the name and you rename them all to "xyz", they're all going to overwrite each other.. or the first "mv" command will rename the first directory to xyz, and all subsequent "mv" commands will move the remaining directories inside of xyz..

For instance, here's some code that does what you're asking (it was done in ksh, so you may need to modify it - i.e. substituting $status for $?):

for i in `ls`; do
 if [ -d $i ]; then
  echo $i | grep -q *abc*
  if [ $? -eq 0 ]; then
   mv $i xyz
  fi
 fi
done

But if you have three directories called
dirabc1
dirabc2
dirabc3
then dirabc1 will be renamed to xyz and dirabc2 and dirabc3 will be moved inside xyz..

all the dirs are "forked" off from each other. there are no directories that contain more than one directory with the same pattern (i hope that makes sense). i understand your point, and i hadn't thought of that. thanks, i'll try your suggestion and post back

thanks again

i tried the following:

.............
#!/bin/ksh
for i in `ls`; do
if [ -d $i ]; then
echo $i | grep -q "*/*/*DUAL*
if [ $? -eq 0 ]; then
mv $i fse
fi
fi
done
..............

there were 10 directories containing one dir each. each 2nd level dir only contained one dir matching *DUAL*. i wanted to rename each of these "fse"

i got the following error repeated 10 times (i suppose once for each of the 10 dirs)

grep: illegal option --q
Usage: grep -hblcnsviw pattern file

have i missed something?

quant

This should do the trick:

for i in `find . -name *somedir*`; do
 mv $i `dirname $i`'/xyz'
done

This could be a one-liner if you used the -exec option of the find command, but I couldn't get it to work right...

You're only renaming directories, so the -type d option for find is a boon. Also, if you really have "hundreds of directories," it's just possible that there are so many that glob to "*abc*' that the shell can't handle the command line. When this is true, I try to use something like this untested code:

find . -type d -name '*abc*' | while read pn; do
    dn=`dirname "$pn"`
    mv "$pn" "$dn/xyz"
done

(Thanks to oombera for the `dirname "$dn"` bit. Somehow I keep forgetting about that ...)

Part of your problem might be filenames that contain spaces --- common on "modern" Windows boxes and not unheard of on Unices --- so I put in an extra statement and some more quotes. If this is guaranteed not to be part of your problem, all the "double quotes" can come out.

You should also really carefully consider the other posters' cautions about duplicate file names, too.

oombera:
i couldn't get that to work. i played with it for a while with different results. i'm not sure of the use of:
mv $i `dirname $i`'/xyz'

i did this:
................
for i in `find . -name */*/*DUAL*`; do
mv $i `*/*/*DUAL* $i`'/fse'
done
................
i got error:
find bad option 1005/15sep01.images/20010915_AXIAL_DUAL_11134
find path-list predicate-list

so, i'm sure it's something i've done wrong. maybe i should clarify my task.

say i have dir "02"...
02 has dirs "1004" and "1005"

1004 has dirs "a" and "b" in it
a has dirs "123abc" and "456def"
b has dirs "124abc" and "457def"

1005 has dirs "c" and "d" in it
c has dirs "125abc" and "458def"
d has dirs "126abc" and "459def"

from the 02 directory i would like to rename all subdirs with dirnames containing the pattern *abc* to "xyz"; and all subdirs with dirnames containing the pattern *def* to "uvw"

in the end i wish to have:
02/1004/a/:
xyz uvw

02/1004/b/:
xyz uvw

02/1005/c/:
xyz uvw

02/1005/d/:
xyz uvw

_________
obviously from my error above i am using *DUAL* instead of *abc* and using fse instead of xyz. i should have explained this more completely from the beginning. me bad.

criglerj: i just saw your post after i posted this. i will try your ideas and post back. thanks

quant

Try criglerj's way too, but replace '*abc*' with '*DUAL*'

Find has the ability to go into subdirectories by itself, so don't try telling it to by using asterisks..

you people rock! i think both ways work, but i used criglerj's way with the heads-up about removing the asterisks. man, you guys have saved me untold amounts of time. i have spent the past week and a half manually doing this, all day everyday. i'm not even half-way done. i wish i had posted sooner.

thanks again