Multiple file rename

I've been googling for days but can't find a solution to this problem.

I have a number of sets of files on a server

file02.dat
.
.
file12.dat

/.../fred(1 to n)/bill(1 to m)/tony/joe/

in any "fred" branch there will be one or more "bill"s
some joe/'s may not have a fileset and could be empty.

the files need to be renumbered file01.dat.. file11.dat

ie. mv file02.dat file01.dat

if you prefer the filenames could be 01file.dat or any variation.

If I can get it to work, this will be a last day of the month cronjob

Is there a solution to this?

Are you saying that there will never be a file01.dat in any of these directories?

Are all of the files in any given directory a contiguous numeric sequence starting with file02.dat? (I.e., could there just be file02.dat, file10.dat, and file11.dat in one of the directories?)

Are there ever any files other than fileXX.dat in the leaf directories?

Do we need to renumber files in directories that aren't leaves in the file system hierarchy?

It's late for me now, but - with just GNU/Linux find and bash - you could start working from here:

find /tmp/fred{1..N}/bill{1..M}/tony/joe/file{02..12}.dat 2>/dev/null | while IFS= read -r filename; do num=${filename: -6:2}; newnum=$(echo "$num - 1" | bc); echo ${filename/%$num.dat/$newnum.new.dat} ; done

For instance:

lem@biggy:/tmp$ find /tmp/fred{1..2}/bill{1..4}/file{02..12}.dat 2>/dev/null
/tmp/fred1/bill3/file02.dat
/tmp/fred1/bill3/file03.dat
/tmp/fred1/bill3/file04.dat
/tmp/fred1/bill3/file05.dat
/tmp/fred1/bill3/file06.dat
/tmp/fred1/bill3/file07.dat
/tmp/fred1/bill3/file08.dat
/tmp/fred1/bill3/file09.dat
/tmp/fred1/bill3/file10.dat
/tmp/fred1/bill3/file11.dat
/tmp/fred1/bill3/file12.dat
/tmp/fred2/bill4/file02.dat
/tmp/fred2/bill4/file03.dat
/tmp/fred2/bill4/file04.dat
/tmp/fred2/bill4/file05.dat
/tmp/fred2/bill4/file06.dat
/tmp/fred2/bill4/file07.dat
/tmp/fred2/bill4/file08.dat
/tmp/fred2/bill4/file09.dat
/tmp/fred2/bill4/file10.dat
/tmp/fred2/bill4/file11.dat
/tmp/fred2/bill4/file12.dat
lem@biggy:/tmp$ find /tmp/fred{1..2}/bill{1..4}/file{02..12}.dat 2>/dev/null | while IFS= read -r filename; do num=${filename: -6:2}; newnum=$(echo "$num - 01" | bc); echo ${filename/%$num.dat/$newnum.new.dat} ; done
/tmp/fred1/bill3/file1.new.dat
/tmp/fred1/bill3/file2.new.dat
/tmp/fred1/bill3/file3.new.dat
/tmp/fred1/bill3/file4.new.dat
/tmp/fred1/bill3/file5.new.dat
/tmp/fred1/bill3/file6.new.dat
/tmp/fred1/bill3/file7.new.dat
/tmp/fred1/bill3/file8.new.dat
/tmp/fred1/bill3/file9.new.dat
/tmp/fred1/bill3/file10.new.dat
/tmp/fred1/bill3/file11.new.dat
/tmp/fred2/bill4/file1.new.dat
/tmp/fred2/bill4/file2.new.dat
/tmp/fred2/bill4/file3.new.dat
/tmp/fred2/bill4/file4.new.dat
/tmp/fred2/bill4/file5.new.dat
/tmp/fred2/bill4/file6.new.dat
/tmp/fred2/bill4/file7.new.dat
/tmp/fred2/bill4/file8.new.dat
/tmp/fred2/bill4/file9.new.dat
/tmp/fred2/bill4/file10.new.dat
/tmp/fred2/bill4/file11.new.dat

HTH.
--
Bye

Hi Guys,

Thanks for the help. When I awoke this morning I must have had a suddden rush of blood to the head and came up with this:

for DIR in fred*/bill*/tony/joe;
do
mv $DIR/filename02.dat $DIR/filename01.dat;
.
.
mv $DIR/filename12.dat $DIR/filename11.dat;
done

It does the job but if there is a more elegant solution I'd be interested to see it.

Actually the first line of the script deletes filename01.dat
there is a blank.dat which the last line copies to filename12.dat to complete the reset. As that is just a file containing "0" it could be located in /root which is where the script is located.

You might try something like:

#!/bin/ksh
basedir=$(pwd)
for dir in fred*/bill*/tony/joe/
do
        if ! cd "$dir"
        then    # No permission, or not-a-directory
                printf "%s: %s not processed\n" "$0" "$dir" >&2
                continue
        fi
        printf "%s: processing directory %s\n" "$0" "$dir" 
        target=file01.dat
        src=2
        while [ $src -le 12 ]
        do
                source=$(printf "file%02d.dat" $src)
                if [ -e $source ]
                then    echo mv $source $target
                else    echo touch $target
                fi
                target=$source
                src=$(( src + 1 ))
        done
        echo touch $target
        cd "$basedir"
done

Remove the "echo " in all three places it occurs if you're convinced that this does what you want.

This creates empty files instead of files containing a "0" for file12.dat and any other missing files in the given directories. If you really want a file containing "0" (with no trailing <newline>), replace both touch $target commands with printf "0" > $target . If you want a more complicated initialization file, create it as a file named initfile.dat in the directory where this script will be started and replace the touch commands with cp "$basedir"/initfile.dat $target commands. If you want to be able to run this when you aren't sitting in the base directory for this file hierarchy, add cd rootdir (where "rootdir" is an absolute pathname to the desired starting point) before the line that sets basedir.

Hope this helps...