LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-27-2009, 10:56 AM   #1
Asy
LQ Newbie
 
Registered: May 2008
Location: The Netherlands
Distribution: Ubuntu
Posts: 25

Rep: Reputation: 16
[Perl] Search for multiple files in multipe directories


Hi all!

Still I'm struggling with a script to remove a lot of log file.

In a previous post I asked for the wanted function to search for files or directories.

Now I'm stuck on the next:

On a server there are a lot of log files is directories.
In (korn)shell the search is simple:
find . -name /dirname1/dirname2/*/dir/*log

I'm now looking for a solution to do the same in perl.

The code below should be driven by an Oracle datebase where each line in @rmlines is filled with the follow options:
server/path where files are:search string:days keep files:type file or directory

If i fill an wildcard in the server/path part, the search doesn't work. Does any one have a suggestion?


Code:
use strict;
use warnings;
use English;
use File::Copy;
use File::Find ();
use Env;
use Cwd ();

use vars qw/*name *dir *prune/;
*name	= *File::Find::name;
*dir	= *File::Find::dir;
*prune	= *File::Find::prune;

sub wanted;

my $directory;
my $filename;
my $saveday;
my $filetype;

sub wanted ($@) {
	my ($dev,$ino,$mode,$nlink,$uid,$gid);
	my $cwd= Cwd::cwd();

	/$filename/s &&
	(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
	( ( $filetype eq 'f' ) ? -f _ : -d _ ) &&
	(int(-M _) > $saveday) &&
	do_action( "${cwd}/$_",$filetype);
}

ub remove_dir {
        my $dir = shift;
	local *DIR;

	opendir DIR, $dir or die "opendir $dir: $!";
	for (readdir DIR) {
	        next if /^\.{1,2}$/;
	        my $path = "$dir/$_";
		print "Stap 4 f verwijderen file : $_\n";
	#	unlink $path or print "Error removing file $path uit dir - $!\n" if -f $path ;
		remove_dir($path) if -d $path;
	}
	closedir DIR;
	print "Stap 4 d verwijderen directory : $dir\n";
	#rmdir $dir or print "Error removing directory $dir - $!\n" if -d $dir ;
}

my @rmlines = ( '//server-x/tmp:^.*\.log|LOG|Log\z:30:f:',
		'//server-y/d$:^Oracle/admin/\.*/adump\*.*:30:f'
		) ;

foreach (@rmlines) 
	s/#.*//;            	# ignore comments by erasing them
        next if /^(\s)*$/;  	# skip blank lines
	($directory, $filename, $saveday, $filetype)=split(":");
	if ( ! -d $directory ) {
		print "Warning: $directory with $filename not found and cleaned\n";
	} else {
		File::Find::find({wanted => \&wanted }, $directory);
	}
};
 
Old 10-27-2009, 12:12 PM   #2
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by Asy View Post
Hi all!

Still I'm struggling with a script to remove a lot of log file.

In a previous post I asked for the wanted function to search for files or directories.

Now I'm stuck on the next:

On a server there are a lot of log files is directories.
In (korn)shell the search is simple:
find . -name /dirname1/dirname2/*/dir/*log

I'm now looking for a solution to do the same in perl.

The code below should be driven by an Oracle datebase where each line in @rmlines is filled with the follow options:
server/path where files are:search string:days keep files:type file or directory

If i fill an wildcard in the server/path part, the search doesn't work. Does any one have a suggestion?


Code:
use strict;
use warnings;
use English;
use File::Copy;
use File::Find ();
use Env;
use Cwd ();

use vars qw/*name *dir *prune/;
*name	= *File::Find::name;
*dir	= *File::Find::dir;
*prune	= *File::Find::prune;

sub wanted;

my $directory;
my $filename;
my $saveday;
my $filetype;

sub wanted ($@) {
	my ($dev,$ino,$mode,$nlink,$uid,$gid);
	my $cwd= Cwd::cwd();

	/$filename/s &&
	(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
	( ( $filetype eq 'f' ) ? -f _ : -d _ ) &&
	(int(-M _) > $saveday) &&
	do_action( "${cwd}/$_",$filetype);
}

ub remove_dir {
        my $dir = shift;
	local *DIR;

	opendir DIR, $dir or die "opendir $dir: $!";
	for (readdir DIR) {
	        next if /^\.{1,2}$/;
	        my $path = "$dir/$_";
		print "Stap 4 f verwijderen file : $_\n";
	#	unlink $path or print "Error removing file $path uit dir - $!\n" if -f $path ;
		remove_dir($path) if -d $path;
	}
	closedir DIR;
	print "Stap 4 d verwijderen directory : $dir\n";
	#rmdir $dir or print "Error removing directory $dir - $!\n" if -d $dir ;
}

my @rmlines = ( '//server-x/tmp:^.*\.log|LOG|Log\z:30:f:',
		'//server-y/d$:^Oracle/admin/\.*/adump\*.*:30:f'
		) ;

foreach (@rmlines) 
	s/#.*//;            	# ignore comments by erasing them
        next if /^(\s)*$/;  	# skip blank lines
	($directory, $filename, $saveday, $filetype)=split(":");
	if ( ! -d $directory ) {
		print "Warning: $directory with $filename not found and cleaned\n";
	} else {
		File::Find::find({wanted => \&wanted }, $directory);
	}
};

Why do you have

Code:
use vars qw/*name *dir *prune/;
*name	= *File::Find::name;
*dir	= *File::Find::dir;
*prune	= *File::Find::prune;
You have a number '_' (not $_) in your code - why ?

What did you do to debug ? I.e. what is the earliest place in your code in which actual behavior differs from actual one ?

Which exactly line with wildcards doesn't work and why (based on what documentation) do you expect it to work ?

What does '//' in

Code:
my @rmlines = ( '//server-x/tmp:^.*\.log|LOG|Log\z:30:f:',
		'//server-y/d$:^Oracle/admin/\.*/adump\*.*:30:f'
		) ;
mean ?
 
Old 10-27-2009, 01:07 PM   #3
Asy
LQ Newbie
 
Registered: May 2008
Location: The Netherlands
Distribution: Ubuntu
Posts: 25

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by Sergei Steshenko View Post
Why do you have

Code:
use vars qw/*name *dir *prune/;
*name	= *File::Find::name;
*dir	= *File::Find::dir;
*prune	= *File::Find::prune;
You have a number '_' (not $_) in your code - why ?
The main part of the script is coming from the command:
find2perl
where you can put the find command mentioned above.

Quote:

What did you do to debug ? I.e. what is the earliest place in your code in which actual behavior differs from actual one ?

Which exactly line with wildcards doesn't work and why (based on what documentation) do you expect it to work ?
I've cleaned up the script by removing all the print statements.
the frase where I'm looking for like

//server-x/tmp/*/otherdir/*.log
the first wildcard is the problem to solve. In the search it doesn't expand at all

Quote:
What does '//' in

Code:
my @rmlines = ( '//server-x/tmp:^.*\.log|LOG|Log\z:30:f:',
		'//server-y/d$:^Oracle/admin/\.*/adump\*.*:30:f'
		) ;
mean ?
The script has to run on Windows server using the unc path to the differend shares.
The @rmline contains 4 parts:
server and path
search files
days to keep the file
choice to remove files or entire directory
 
Old 10-27-2009, 02:19 PM   #4
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by Asy View Post
The main part of the script is coming from the command:
find2perl
where you can put the find command mentioned above.



I've cleaned up the script by removing all the print statements.
the frase where I'm looking for like

//server-x/tmp/*/otherdir/*.log
the first wildcard is the problem to solve. In the search it doesn't expand at all



The script has to run on Windows server using the unc path to the differend shares.
The @rmline contains 4 parts:
server and path
search files
days to keep the file
choice to remove files or entire directory
Well, if you are under Windows, how can you be sure your file paths contain '/' and not '\' ? At all. you can write portably, read

perldoc File::Spec
.

Regarding the wildcard. I guess you are want your regular expression to match. So, have you taken an example path which is supposed to match, and your regular expression, and checked that the expression really works ?

I mean, in such cases I do not trust myself and if I want to check that, say,

/foo/bar/doo.txt

matches

|/foo/bar/*\.txt$|

I am writing a junk script more or less like this:

Code:
my $line = '/foo/bar/doo.txt';
my $re = '/foo/bar/*\.txt$';
$line =~ m|$re| and warn "\$line=$line matches \$re=$re";
My point is that if you suspect the regular expression doesn't work, isolate the case and don't overload yourself and us with unrelated code.

The same applies to other functional parts.
 
Old 10-28-2009, 08:41 AM   #5
Asy
LQ Newbie
 
Registered: May 2008
Location: The Netherlands
Distribution: Ubuntu
Posts: 25

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by Sergei Steshenko View Post
Well, if you are under Windows, how can you be sure your file paths contain '/' and not '\' ? At all. you can write portably, read

perldoc File::Spec
perl is able to handle the forward / as a backward \ running in a Windows environment. I've testing done with this and it's working smoothly.

I've cleanup my code so the problem will be clear:

logfile are appearing in separate dir like

c:/tmp/logdir1/log/*.log
c:/tmp/logdir2/log/*.log
c:/tmp/logdir3/log/*.log

Cleaned code till now:

Code:
#! C:\Perl\bin\perl.exe -w
use strict;
use File::Find ();

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name  = *File::Find::name;
*dir      = *File::Find::dir;
*prune  = *File::Find::prune;

#my $searchdir='c:/tmp/logdir1/dir2'; # this is working!
my $searchdir="c:/tmp/*/dir2";        # like this is working too!
my $searchfile='^.*\.log\z';

sub wanted;

# Traverse desired filesystems
print "Zoekdir = $searchdir \n";
File::Find::find({wanted => \&wanted}, "$searchdir");

exit;

sub wanted {
	my ($dev,$ino,$mode,$nlink,$uid,$gid);
	/$searchfile/s &&
	print("$name\n");
}
The base is created by find2perl:
find2perl c:/tmp/*/log -name *.log

The problem appears on the working out of the var $searchdir. It doesn't work out to the 3 separate dirs/log.

Last edited by Asy; 10-28-2009 at 11:24 AM.
 
Old 10-28-2009, 12:00 PM   #6
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by Asy View Post
perl is able to handle the forward / as a backward \ running in a Windows environment. I've testing done with this and it's working smoothly.

I've cleanup my code so the problem will be clear:

logfile are appearing in separate dir like

c:/tmp/logdir1/log/*.log
c:/tmp/logdir2/log/*.log
c:/tmp/logdir3/log/*.log

Cleaned code till now:

Code:
#! C:\Perl\bin\perl.exe -w
use strict;
use File::Find ();

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name  = *File::Find::name;
*dir      = *File::Find::dir;
*prune  = *File::Find::prune;

#my $searchdir='c:/tmp/logdir1/dir2'; # this is working!
my $searchdir="c:/tmp/*/dir2";        # like this is working too!
my $searchfile='^.*\.log\z';

sub wanted;

# Traverse desired filesystems
print "Zoekdir = $searchdir \n";
File::Find::find({wanted => \&wanted}, "$searchdir");

exit;

sub wanted {
	my ($dev,$ino,$mode,$nlink,$uid,$gid);
	/$searchfile/s &&
	print("$name\n");
}
The base is created by find2perl:
find2perl c:/tmp/*/log -name *.log

The problem appears on the working out of the var $searchdir. It doesn't work out to the 3 separate dirs/log.

Regarding
Quote:
for the convenience of &wanted calls, including -eval statements
- it's really a bad idea to mess up global name space.

You can use a scalar reference, e.g.:


Code:
my $name_ref = \$File::Find::name;
...
my $name = $$name_ref; # dereferencing
Regarding

Quote:
Quote:
perl is able to handle the forward / as a backward \ running in a Windows environment
- of course it can, but the question is how path separator is reported by File::Find module.

Regarding

Code:
File::Find::find({wanted => \&wanted}, "$searchdir");
- you do not need quotes.

Now, what doesn't work ? I.e. now your code performs just file search, so does it find the files you expect it to find ?
 
Old 10-28-2009, 01:48 PM   #7
Asy
LQ Newbie
 
Registered: May 2008
Location: The Netherlands
Distribution: Ubuntu
Posts: 25

Original Poster
Rep: Reputation: 16
Thanks for the remarks!
I'm rearly new to Perl and I will create nice scripts.

Quote:
Now, what doesn't work ? I.e. now your code performs just file search, so does it find the files you expect it to find ?
The script will find the files mentioned only as the complete path is given. The perpose is to make the path variable as well, eg search in several path with one statement, using a wildcard in the pathname.

Tanks in advance.
 
Old 10-28-2009, 02:20 PM   #8
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by Asy View Post
Thanks for the remarks!
I'm rearly new to Perl and I will create nice scripts.



The script will find the files mentioned only as the complete path is given. The perpose is to make the path variable as well, eg search in several path with one statement, using a wildcard in the pathname.

Tanks in advance.
I don't think you can use wildcard in file name in UNIX/Windows sense, but you should rather use a regular expression.

I think you are overcomplicating your development. You have to accept the stages approach (regardless of language). I mean for your case:

1) find all the files under a given directory root and put them into an array;

2) run a loop over the array using the needed in your opinion regular expression checking whether it works as expected. The word "checking" means s comparing the array element to be matched and the regular expression and analyzing why it doesn't work as expected.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[perl] find2perl dynamic search for files or directories Asy Programming 4 07-13-2009 06:10 PM
Search for files only in directories you have sufficient permissions tepez Linux - Software 1 04-08-2007 10:07 AM
Change text in multiple files in multiple directories vivo2341 Linux - General 5 11-27-2006 08:16 PM
need to search (grep) multiple directories red_nexus Linux - Newbie 5 07-04-2006 10:44 PM
Perl: Search and replace directories within text files Erhnam Programming 2 03-07-2006 04:07 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:46 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration