Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Copy the latest file in multiple directory

Status
Not open for further replies.

subok

MIS
Feb 21, 2005
37
BE
Hi,
Any help to a newbie will greatly appreciated.

I'm trying to write MS DOS batch file to check the 4 latest file in a directoty containing several subdirectories.
d:\subok
\10
\20
\30
\40
\50

New can come and stored in any of the sub-dir (10,20,...). Goal is to copy the 4 newest file.

THanks.

Kr,
Richard

 
Since this is a UNIX Scripting forum, I'd recommend doing this by installing Cygwin and writing a bash script (that's how I'd do it).

Or, if you wanted to be Windows-y and are running a supported OS (which OS exactly, by the way?) you could use PowerShell, see forum1619.

Otherwise if it must be MS-DOS you may have some luck in one of the Windows forums.

Annihilannic
[small]tgmlify - code syntax highlighting for your tek-tips posts[/small]
 
Thanks. I reposted the thread in MS Powershell
 
Sorry, was suffering from forum dyslexia. :)

Of course Perl would be a good option for this script too!

Annihilannic
[small]tgmlify - code syntax highlighting for your tek-tips posts[/small]
 
As penance I've written a solution in Perl (tested using Strawberry Perl under Win XP):

Perl:
[COLOR=#006600]#!/usr/bin/perl -w[/color]
[COLOR=#0000FF]use[/color] strict;
[COLOR=#0000FF]use[/color] File::Copy;
[COLOR=#0000FF]my[/color] $srcdir=[COLOR=#808080]"c:\\temp\\tektips\\subok2"[/color];
[COLOR=#0000FF]my[/color] $tgtdir=[COLOR=#808080]"c:\\temp\\tektips\\subok2\\copies"[/color];
[COLOR=#0000FF]my[/color] @fileinfo;
[COLOR=#0000FF]my[/color] $i=[COLOR=#FF0000]0[/color];

[COLOR=#FF0000]chdir[/color] $srcdir [COLOR=#FF8000]or[/color] [COLOR=#FF0000]die[/color] [COLOR=#808080]"unable to change to $srcdir"[/color];

[COLOR=#006600]# find dirs matching 10, 20, ...[/color]
[COLOR=#FF0000]opendir[/color] D,$srcdir [COLOR=#FF8000]or[/color] [COLOR=#FF0000]die[/color] [COLOR=#808080]"unable to open $srcdir"[/color];
[COLOR=#0000FF]my[/color] @subdirs = [COLOR=#FF0000]grep[/color] { /^[[COLOR=#FF0000]0[/color]-[COLOR=#FF0000]5[/color]][COLOR=#FF0000]0[/color]$/ } [COLOR=#FF0000]readdir[/color](D);
[COLOR=#FF0000]closedir[/color] D;

[COLOR=#006600]# find files in those dirs[/color]
[COLOR=#0000FF]foreach[/color] [COLOR=#0000FF]my[/color] $dir (@subdirs) {
	[COLOR=#FF0000]opendir[/color] D,$dir [COLOR=#FF8000]or[/color] [COLOR=#FF0000]die[/color] [COLOR=#808080]"unable to open $dir"[/color];
	[COLOR=#0000FF]my[/color] @files = [COLOR=#FF0000]grep[/color] { !/^[.]/} [COLOR=#FF0000]readdir[/color](D);
	[COLOR=#006600]# store their names and modification times[/color]
	[COLOR=#0000FF]foreach[/color] [COLOR=#0000FF]my[/color] $file (@files) {
		$fileinfo[$i]{name} = $dir . [COLOR=#808080]"\\"[/color] . $file;
		$fileinfo[$i++]{mtime} = ([COLOR=#FF0000]stat[/color]($fileinfo[$i]{name}))[[COLOR=#FF0000]9[/color]];
	}
	[COLOR=#FF0000]closedir[/color] D;
}

[COLOR=#006600]# sort the files by modification time, process the last 4[/color]
[COLOR=#0000FF]foreach[/color] [COLOR=#0000FF]my[/color] $file (([COLOR=#FF0000]sort[/color] { ${$a}{mtime} <=> ${$b}{mtime} } @fileinfo)[-[COLOR=#FF0000]4[/color]..-[COLOR=#FF0000]1[/color]]) {
	[COLOR=#FF0000]print[/color] [COLOR=#808080]"Copying file ${$file}{name} (modified "[/color] . [COLOR=#FF0000]localtime[/color](${$file}{mtime}) . [COLOR=#808080]") to $tgtdir\n"[/color];
	copy(${$file}{name},$tgtdir) [COLOR=#FF8000]or[/color] [COLOR=#FF0000]die[/color] [COLOR=#808080]"Copy failed: $!"[/color];
}

Annihilannic
[small]tgmlify - code syntax highlighting for your tek-tips posts[/small]
 
Hi,

My server is using active PERL i'm trying to adapt the proposed script but i'm stucked at line 23
The directory structure was also changed :

T:\CFS\MP\Monday
\Hour0
\Hour1
\Hour10
\Hour11
\Hour12
\Hour13
\Hour14
\Hour15
\Hour16
\Hour17
\Hour18
\Hour19
\Hour2
\Hour20
\Hour21
\Hour22
\Hour23
\Hour3
\Hour4
\Hour5
\Hour6
\Hour7
\Hour8
\Hour9



/** compiling error
T:\script>test.pl
syntax error at T:\script\test.pl line 23, near "$dir ("
Global symbol "@srcdir" requires explicit package name at T:\script\test.pl line 23.
Global symbol "$dir" requires explicit package name at T:\script\test.pl line 24.
Global symbol "$dir" requires explicit package name at T:\script\test.pl line 24.
syntax error at T:\script\test.pl line 32, near "}"
Execution of T:\script\test.pl aborted due to compilation errors.
/**

//***** script ******
#!d:\bin\perl.exe -w
#use warnings;
use lib 'd:/perl/site/lib';
use strict;
use File::Copy;

my $srcdir="T:/cfs/mp/monday/";
my $tgtdir="T:/script/";
my @fileinfo;
my $i=0;
#my @subdirs;

chdir $srcdir;

# find dirs in scrdir
opendir (DIR,$srcdir) or die "unable to open $srcdir";
while (($srcdir = readdir(DIR))) {
printf ("$srcdir\n");
}
closedir(DIR)

# find files in those dirs
foreach my $dir (@srcdir) {
opendir (D,$dir) or die "unable to open $dir";
my @files = grep { !/^[.]/} readdir(D);
# store their names and modification times
foreach my $file (@files) {
$fileinfo[$i]{name} = $dir . "\\" . $file;
$fileinfo[$i++]{mtime} = (stat($fileinfo[$i]{name}))[9];
}
closedir D;
}

# sort the files by modification time, process the last 4
foreach my $file ((sort { ${$a}{mtime} <=> ${$b}{mtime} } @fileinfo)[-4..-1]) {
print "Copying file ${$file}{name} (modified " . localtime(${$file}{mtime}) . ") to $tgtdir\n";
copy(${$file}{name},$tgtdir) or die "Copy failed: $!";
}
 
You are trying to use the same $srcdir variable for two different things... which won't work. Any reason why you stopped using @subdirs?

If you don't like the original grep usage, you could do something like this:

Code:
...
# find dirs in srcdir
my @subdirs;
opendir (DIR,$srcdir) or die "unable to open $srcdir";
while ((my $dir = readdir(DIR))) {
    push @subdirs,$dir;
}
closedir(DIR)

foreach my $dir (@subdirs) {
...

But note that you may need to do special handling of the "." and ".." directories.

Annihilannic
[small]tgmlify - code syntax highlighting for your tek-tips posts[/small]
 
Thanks Annihilannic,

I modifed it a little a bit to adapt the according to my need and it is working perfectly now, below is code.

But I have one more favor to ask, these copied file are in CSV format and the filenames can be any, I need to search a particular string in line.
For example :
allAssociationUtilizationData;EWSDV16SG;2012/08/24;07:00:00;STP01.99;900;FALSE;SCANNER;10;8253;7611;16235;11998;2063216;1369640;0;1570236;972272;0

I need to search the line with "STPAM01.99" in column 5 and "10" in column 9 in one file and "STPAR02.99" in column 5 and "10" in column 9 in the other file.

Afterwards divide the value of column 14 with value of column 13 of the row for each file.
Depending on the result if it's > .50 script will call "low.bat" batch file.

Any suggestion on how to proceed.

Thanks a lot!

Perl:
#!d:\bin\perl.exe -w
#use warnings;
use lib 'd:/perl/site/lib';
use strict;
use File::Copy;

my $srcdir="T:/cfs/mp/monday/";
my $tgtdir="T:/script";
my @fileinfo;
my $i=0;

chdir $srcdir or die "unable to change to $srcdir";

# find dirs matching time
opendir D,$srcdir or die "unable to open $srcdir";
my @subdirs = grep { /^[Hour]/ } readdir(D);
closedir D;;

# find files in those dirs
foreach my $dir (@subdirs) {
	opendir D,$dir or die "unable to open $dir";
	my @files = grep { /PM_SCANREP_STP/} readdir(D);
	# store their names and modification times
	foreach my $file (@files) {
		$fileinfo[$i]{name} = $dir . "\\" . $file;
		$fileinfo[$i++]{mtime} = (stat($fileinfo[$i]{name}))[9];
	}
	closedir D;
}

# sort the files by modification time, process the last 2
foreach my $file ((sort { ${$a}{mtime} <=> ${$b}{mtime} } @fileinfo)[-2..-1]) {
	print "Copying file ${$file}{name} (modified " . localtime(${$file}{mtime}) . ") to $tgtdir\n";
	print ${$file}{name};
	copy(${$file}{name},$tgtdir) or die "Copy failed: $!";
}

 
One minor correction to your code: grep { /^[Hour]/ } should just be grep { /^Hour/ }. "^[Hour]" would match any filename beginning with the letters "H", "o", "u" or "r", whereas "^Hour" matches any filename beginning with the word "Hour".

I'm not sure I really understand your requirements, but this untested code should give you some ideas...

Perl:
[COLOR=#006600]# ...[/color]

[COLOR=#006600]# sort the files by modification time, process the last 2[/color]
[COLOR=#0000FF]my[/color] @copiedfiles;
[COLOR=#0000FF]foreach[/color] [COLOR=#0000FF]my[/color] $file (([COLOR=#FF0000]sort[/color] { ${$a}{mtime} <=> ${$b}{mtime} } @fileinfo)[-[COLOR=#FF0000]2[/color]..-[COLOR=#FF0000]1[/color]]) {
	[COLOR=#FF0000]print[/color] [COLOR=#808080]"Copying file ${$file}{name} (modified "[/color] . [COLOR=#FF0000]localtime[/color](${$file}{mtime}) . [COLOR=#808080]") to $tgtdir\n"[/color];
	[COLOR=#FF0000]print[/color] ${$file}{name};
	copy(${$file}{name},$tgtdir) [COLOR=#FF8000]or[/color] [COLOR=#FF0000]die[/color] [COLOR=#808080]"Copy failed: $!"[/color];
        [COLOR=#FF0000]push[/color] @copiedfiles,[COLOR=#808080]"$tgtdir/${$file}{name}"[/color];
} 

[COLOR=#0000FF]foreach[/color] [COLOR=#0000FF]my[/color] $file (@copiedfiles) {
        [COLOR=#FF0000]open[/color] FILE,$file [COLOR=#FF8000]or[/color] [COLOR=#FF0000]die[/color] [COLOR=#808080]"unable to open $file"[/color];
        [COLOR=#0000FF]while[/color] (<FILE>) {
                 [COLOR=#0000FF]my[/color] @a=[COLOR=#FF0000]split[/color](/,/);
                 [COLOR=#0000FF]if[/color] ($a[[COLOR=#FF0000]4[/color]] [COLOR=#FF8000]eq[/color] [COLOR=#808080]"STPAM01.99"[/color] && $a[[COLOR=#FF0000]9[/color]]==[COLOR=#FF0000]10[/color] && $a[[COLOR=#FF0000]13[/color]]/$a[[COLOR=#FF0000]12[/color]] > [COLOR=#FF0000]0[/color].[COLOR=#FF0000]5[/color]) { [COLOR=#FF0000]system[/color]([COLOR=#808080]"c:/somepath/low.bat $file"[/color]); }
                 [COLOR=#0000FF]if[/color] ($a[[COLOR=#FF0000]4[/color]] [COLOR=#FF8000]eq[/color] [COLOR=#808080]"STPAR02.99"[/color] && $a[[COLOR=#FF0000]9[/color]]==[COLOR=#FF0000]10[/color] && $a[[COLOR=#FF0000]13[/color]]/$a[[COLOR=#FF0000]12[/color]] > [COLOR=#FF0000]0[/color].[COLOR=#FF0000]5[/color]) { [COLOR=#FF0000]system[/color]([COLOR=#808080]"c:/somepath/low.bat $file"[/color]); }
        }
        [COLOR=#FF0000]close[/color] FILE;
}

Annihilannic
[small]tgmlify - code syntax highlighting for your tek-tips posts[/small]
 
Thanks.

I have inserted your proposal accoring to my need but i'm getting to following error when running it.

/**
Use of uninitialized value in string eq at T:\script\test3.pl line 44, <FILE> line 98
Use of uninitialized value in string eq at T:\script\test3.pl line 45, <FILE> line 98
/**

The idea of this script is to look for the 2 latest file in a source directory that contains several sub-directory.
The copied files are CSV and i need to divide the value of column 13 and 12 if the condition column 4 and 9 are met.
depending on the result a DOS batch is called.

Code:
#!d:\bin\perl.exe -w
#use warnings;
use lib 'd:/perl/site/lib';
use strict;
use File::Copy;

my $srcdir="T:/cfs/mp/monday/";
my $tgtdir="T:/script";
my @fileinfo;
my $i=0;
my @spf = glob "t:/script/*.spf";


chdir $srcdir or die "unable to change to $srcdir";

# find dirs matching time
opendir D,$srcdir or die "unable to open $srcdir";
my @subdirs = grep { /^Hour/ } readdir(D);
closedir D;;

# find files in those dirs
foreach my $dir (@subdirs) {
	opendir D,$dir or die "unable to open $dir";
	my @files = grep { /PM_SCANREP_STP/} readdir(D);
	# store their names and modification times
	foreach my $file (@files) {
		$fileinfo[$i]{name} = $dir . "\\" . $file;
		$fileinfo[$i++]{mtime} = (stat($fileinfo[$i]{name}))[9];
	}
	closedir D;
}

# sort the files by modification time, process the last 2
foreach my $file ((sort { ${$a}{mtime} <=> ${$b}{mtime} } @fileinfo)[-2..-1]) {
	print "Copying file ${$file}{name} (modified " . localtime(${$file}{mtime}) . ") to $tgtdir\n";
	print ${$file}{name};
	copy(${$file}{name},$tgtdir) or die "Copy failed: $!";
} 

foreach my $file (@spf) {
	open FILE, "< $file" or die "Cannot open $file for read\n$!";       
        while (<FILE>) {
                 my @a=split(/,/);
	         if ($a[4] eq "STPAM01.47" && $a[9]==10 && $a[13]/$a[12] > 0.5) { system("t:/script/low.bat"); }
	         if ($a[4] eq "STPAR02.47" && $a[9]==10 && $a[13]/$a[12] > 0.5) { system("t:/script/low2.bat"); }           

        }
        close FILE;
}
 
And what is on line 98 of the input file? My guess is that it doesn't have 14 fields...

Annihilannic
[small]tgmlify - code syntax highlighting for your tek-tips posts[/small]
 
Thanks Annihilannic,

the last feedback gave me hint, i forgot that my cvs is actually semi-colon separated.
after changing in the split function /,/ with /;/... it worked!!

Kr,
Richard
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top