views:

139

answers:

3

I have a directory structure that looks like this:

/a/f.xml
/b/f.xml
/c/f.xml
/d/f.xml

What I want to do is copy all the xml files into one directory like this:

/e/f_0.xml
/e/f_1.xml
/e/f_2.xml
/e/f_3.xml

How can I do that efficiently on the Linux shell?

A: 
let count=0
for file in $(ls $dir)
do
mv $file $newdir/${file%%.*}_$count.${file##*.}
let count=count+1
done
ennuikiller
@ennuikiller: that's a cool one...shouldnt that ls be recursive to pick out the *.xml...?? +1 from me :D
tommieb75
why not use something like `find $dir -type f -name "*.xml"` in place of `ls $dir`?
jschmier
Don't use `ls` and you shouldn't use `for` either. Pipe `find` into `while`. Also, this doesn't recurse into the source directories and it picks up all the files rather than just the xml files.
Dennis Williamson
@dennis,@jschier"Every subdirectory contains the same filenames, so yes, the number should be appended to every file" - op and yes while in general is preferred because it deals with spaces in filenames, but it is not necessary in this case
ennuikiller
-1 for useless use of `ls`. use shell expansion
ghostdog74
A: 
#!/bin/bash
COUNTER=0;
for i in */f.xml;
do
    BASE=`expr "$i" : '.*/\(.*\)\..*'`;
    EXT=`expr "$i" : '.*/.*\.\(.*\)'`;
    mv "$i" e/"$BASE"_"$COUNTER"."$EXT";
    COUNTER=`expr $COUNTER + 1`
done;
Valentin Rocher
A: 
#!/bin/bash
for file in /{a,b,c,d}/f.xml
do
    name=${file##*/}
    name=${name%.xml}
    ((i++))
    echo mv "$file" "/destination/${name}_${i}.xml"
done

bash 4.0 (for recursive)

shopt -s globstar
for file in /path/**/f.xml
do
    name=${file##*/}
    name=${name%.xml}
    ((i++))
    echo mv "$file" "/destination/${name}_${i}.xml"
done
ghostdog74