LinuxQuestions.org
Share your knowledge at the LQ Wiki.
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 12-15-2008, 09:09 AM   #1
HyperTrey
Member
 
Registered: Sep 2006
Posts: 127

Rep: Reputation: 15
Exclamation Creating a Perl Program with options


I am looking to create a program that will allow me to specify which files to use at command line. We want to use pure perl if we can.

I am looking for something like: ./MyProgram -f[3] file1, file2, file3

where the -f[3] specifies the number of files and then list of file names.



would I be using Getopt::Std and Getopt::Long? or How would I get it to use the files listed in a directory without hard coding the names?
 
Old 12-15-2008, 11:30 AM   #3
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 59
I use something like this in a script:

Code:
GetOptions(
  'help!'   =>  \$opt_help,            
  'man!'    =>  \$opt_man,
  'full!'    =>  \$opt_full,
  'svn:i'  =>  \$opt_svn,              # i is for an integer value
  'admin:s'   =>  \$opt_admin,         # s expects a string value
)

# Later...
list_admin($opt_admin, %blogs);

# Later still...
sub list_admin {
  my($opt_admin, %blogs) = @_;         # Assign what we pass into the subroutine
  
  my @wanted = split /,/, $opt_admin;  # Split the comma-separated string
                                       # into an array, so we can process
                                       # individual values easily
# Do more interesting stuff
}
The user then enters --admin bob,john,julie and the script reads the csv into $opt_admin. Then we split and deal with that value later in a subroutine. Check the documentation for Getopt::Long for more details, but it's not too hard.

Last edited by Telemachos; 12-15-2008 at 11:32 AM.
 
Old 12-15-2008, 01:08 PM   #4
HyperTrey
Member
 
Registered: Sep 2006
Posts: 127

Original Poster
Rep: Reputation: 15
OK , I want to use a backup where if it has no arguments then it will run it on all files in the directory. How do I populate an array with the list of files in the directory?
 
Old 12-15-2008, 01:57 PM   #5
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 453Reputation: 453Reputation: 453Reputation: 453Reputation: 453
Quote:
Originally Posted by HyperTrey View Post
OK , I want to use a backup where if it has no arguments then it will run it on all files in the directory. How do I populate an array with the list of files in the directory?
perldoc perlfunc -> opendir -> readdir .
 
Old 12-15-2008, 02:46 PM   #6
HyperTrey
Member
 
Registered: Sep 2006
Posts: 127

Original Poster
Rep: Reputation: 15
Alright this is what I got now:

Code:
if ($ARGV[0] eq "-d") {
	# print "$ARGV[1]\n";

	opendir(DIR, $ARGV[1]) || die("Directory does not exist.  Please Check spelling.\n");
	@dir = readdir(DIR);
	foreach $file (@dir) {
 		print "$file" . "\n";
	}
	closedir(DIR);
}
It works perfectly, but how do I check the file extensions to make sure that the file name is correct (IE FILE_2008_02.LOG)? I know I could simply do a
Code:
if ($file =~ /\.LOG/)
But there are some .LOG.BAK files and I only want the .LOG files.
 
Old 12-15-2008, 02:58 PM   #7
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 453Reputation: 453Reputation: 453Reputation: 453Reputation: 453
Quote:
Originally Posted by HyperTrey View Post
Alright this is what I got now:

Code:
if ($ARGV[0] eq "-d") {
	# print "$ARGV[1]\n";

	opendir(DIR, $ARGV[1]) || die("Directory does not exist.  Please Check spelling.\n");
	@dir = readdir(DIR);
	foreach $file (@dir) {
 		print "$file" . "\n";
	}
	closedir(DIR);
}
It works perfectly, but how do I check the file extensions to make sure that the file name is correct (IE FILE_2008_02.LOG)? I know I could simply do a
Code:
if ($file =~ /\.LOG/)
But there are some .LOG.BAK files and I only want the .LOG files.
The
Quote:
"Directory does not exist. Please Check spelling.\n"
is not necessarily correct. There may be failure to open a directory because user does not have 'x' ot 'r' permission.

Your error message is very unfriendly because it does not include the directory name.

You better use lexical variables and not global handles, i.e.

Code:
opendir(my $dh, $ARGV[1]) or die "ERROR can not open $ARGV[1] directory";
 
Old 12-15-2008, 03:15 PM   #8
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 59
Quote:
Originally Posted by HyperTrey View Post
I know I could simply do a
Code:
if ($file =~ /\.LOG/)
But there are some .LOG.BAK files and I only want the .LOG files.
You can use an anchor to specify that you only want .LOG:
Code:
if ($file =~ /\.LOG$/) {
  # Do stuff here
}
See here: http://perldoc.perl.org/perlrequick....-word-matching (anchors are at the bottom of this section of the page).

Edit: By the way, Getopt::Long is a lot more flexible and powerful than manually messing with $ARGV[0], $ARGV[1] and company.

Last edited by Telemachos; 12-15-2008 at 03:20 PM.
 
Old 12-16-2008, 08:13 AM   #9
HyperTrey
Member
 
Registered: Sep 2006
Posts: 127

Original Poster
Rep: Reputation: 15
Code:
while ($pointer <= $#dir) {
		if ($dir[$pointer] =~ /\.LOG$/) {
			#if ($dir[pointer] =~ (/_/) {
 			$pointer++;
		}
		else {
			splice(@dir, $pointer, 1);
		}
		print "$dir[$pointer]" . "\n";
	}
Still shows the .LOG.bak files. What did I do wrong here?

Last edited by HyperTrey; 12-16-2008 at 08:17 AM. Reason: code was wrong
 
Old 12-16-2008, 08:48 AM   #10
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 453Reputation: 453Reputation: 453Reputation: 453Reputation: 453
Quote:
Originally Posted by HyperTrey View Post
Code:
while ($pointer <= $#dir) {
		if ($dir[$pointer] =~ /\.LOG$/) {
			#if ($dir[pointer] =~ (/_/) {
 			$pointer++;
		}
		else {
			splice(@dir, $pointer, 1);
		}
		print "$dir[$pointer]" . "\n";
	}
Still shows the .LOG.bak files. What did I do wrong here?
I think your

Code:
print "$dir[$pointer]" . "\n";
statement is in a wrong place.

And why simply not to write

Code:
print "$dir[$pointer]\n";
?

Better yet, since this is for debugging,

Code:
warn "\$dir[$pointer]=$dir[$pointer]";
 
Old 12-16-2008, 09:05 AM   #11
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 59
The print statement is executed no matter what regex you put in the if test, since it's not in the block of code controlled by the if test (as Sergei said). Here's your code with spaces and comments to clarify:
Code:
while ($pointer <= $#dir) {
		if ($dir[$pointer] =~ /\.LOG$/) {
			# Stuff here happens if $dir[$pointer] matches regex
 			$pointer++;
		}
		else {
                        # Stuff here happens if $dir[$pointer] doesn't match regex
			splice(@dir, $pointer, 1);
		}

                # This happens every time through the while loop, no matter what happens in the test above
		print "$dir[$pointer]" . "\n";
	}
 
Old 12-16-2008, 09:48 AM   #12
HyperTrey
Member
 
Registered: Sep 2006
Posts: 127

Original Poster
Rep: Reputation: 15
I am sorry I am being a pain, however I still can not get this to work correctly. As I have said, I have in there .LOG.bak files, file1_2008_07.log type files and regular file1.LOG file. What I am trying to do is to weed out the master files of just plain file1.log and the .LOG.bak files and ONLY use the 2008_07.LOG files so we can do month to month fiscal data. I have the mechanism here, I just can't see what I did wrong. I did not catch the printing being in the wrong spot.

Code:
        @dir = readdir(DIR);
	$pointer = 0;
	while ($pointer <= $#dir) {
		if ($dir[$pointer] =~ /\.LOG$/) {
			#if ($dir[$pointer] =~ /\_/) {
				$pointer++;
				print "$dir[$pointer]\n";
			#}
		}
		else {
			#print "test\n";
			splice(@dir, $pointer, 1);
		}
	}
	closedir(DIR);

Above is the code that has been corrected but still has the Master file and the .LOG.bak files. I tried:

Code:
        foreach $file (@dir) {
 		print "$file" . "\n";
	}
	closedir(DIR);
I was not sure how to remove the array element without using the index. Is there a better way to populate and filter the array than what I am doing?
 
Old 12-16-2008, 10:05 AM   #13
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 59
Ok, there are two separate issues here, I think: the @dir array and the regular expression test. Are you trying to keep certain items out of the @dir array? If so, you need to apply the regex test when you build that array. For example,
Code:
my @dir = grep { /\.LOG$/ } readdir DIR
You are only using the regex later, after the @dir array has already been populated. See here for more on the grep function.

Or am I confused? Are you still seeing the LOG.bak items in the print statement?

Last edited by Telemachos; 12-16-2008 at 10:07 AM.
 
Old 12-16-2008, 11:04 AM   #14
HyperTrey
Member
 
Registered: Sep 2006
Posts: 127

Original Poster
Rep: Reputation: 15
Thank you so very much for you help. I have the working code here and I want to make sure anyone else who has the same situation has the answer Thank you again for helping me, I am still learning the advance stuff.

Code:
opendir(DIR, $ARGV[1]) or die "ERROR can not open $ARGV[1] directory\n";
	
	my @dir = grep { /\.LOG$/ } readdir(DIR);
	$pointer = @dir;
	print "$pointer files\n";
	for ($i=0; $i<$pointer; $i++) {
		if ($dir[$i] =~ /\_/) {
			print "$dir[$i]\n";
		}
	}
	closedir(DIR);
 
Old 12-16-2008, 01:27 PM   #15
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 453Reputation: 453Reputation: 453Reputation: 453Reputation: 453
Quote:
Originally Posted by HyperTrey View Post
Thank you so very much for you help. I have the working code here and I want to make sure anyone else who has the same situation has the answer Thank you again for helping me, I am still learning the advance stuff.

Code:
opendir(DIR, $ARGV[1]) or die "ERROR can not open $ARGV[1] directory\n";
	
	my @dir = grep { /\.LOG$/ } readdir(DIR);
	$pointer = @dir;
	print "$pointer files\n";
	for ($i=0; $i<$pointer; $i++) {
		if ($dir[$i] =~ /\_/) {
			print "$dir[$i]\n";
		}
	}
	closedir(DIR);

This all is bad.

No lexical variables, so everything is global.

$pointer is a strange name - the variable actually contains number of elements in @dir.

The whole

Code:
for ($i=0; $i<$pointer; $i++)
part is much better written in this context as

Code:
foreach my $file(@dir)
  {
  warn "\$file=$file";
  }
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
src2pkg and mod_perl ( perl mods with options ) rpedrica Slackware 10 11-19-2008 12:42 AM
LXer: Parsing Options in Shell, Perl and C LXer Syndicated Linux News 0 04-16-2007 01:01 AM
Creating patch file which options to use? cranium2004 Linux - Newbie 1 03-13-2005 04:35 AM
Creating patch file which options to use? cranium2004 Programming 1 03-11-2005 09:56 PM
compiling perl with c options fobius Slackware 1 10-06-2004 09:05 PM


All times are GMT -5. The time now is 06:05 AM.

Main Menu
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
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration