CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
[SOLVED] Opening check for more files

 



teardrop
Novice


Jan 14, 2014, 10:03 AM

Post #1 of 11 (2294 views)
[SOLVED] Opening check for more files Can't Post

Hi all,
I'm writing a small script to edit some file and I want to pass the files path from command line, like this:

./foo myfile.txt anotherfile.txt

So I'm using a for loop:


Code
if(@ARGV<1) 
{
print "Usage: nameprog FILE [FILE...]\n";
exit(0);
}
for(my $i=0;$i<@ARGV;$i++)
{
my $filename=$ARGV[$i];
if( open(FILE,"$filename") )
{
#bunch of code
}
else
{
print "$filename : No such file or directory\n";
}
}


I can't use open(FILE,"$filename) or die "Error"; as usual because I don't want to stop the script if I find that only a file can't be opened, so I want know if I'm doing it right.


(This post was edited by teardrop on Jan 15, 2014, 8:32 PM)


FishMonger
Veteran / Moderator

Jan 14, 2014, 11:33 AM

Post #2 of 11 (2288 views)
Re: [teardrop] Opening check for more files [In reply to] Can't Post

Yes, you could do it that way, but there are cleaner ways to do it.


Code
@ARGV or die "Usage: $0 file1 [file2 file3 ...]"; 

FILE:
foreach my $file ( @ARGV ) {
open my $fh, '<', $file
or do {
warn "failed to open $file <$!>";
next FILE;
}
# process the file as needed
}



BillKSmith
Veteran

Jan 14, 2014, 11:58 AM

Post #3 of 11 (2284 views)
Re: [FishMonger] Opening check for more files [In reply to] Can't Post

Note that there are two minor differences between FishMonger's version and the original. Both are probably improvements.

Error messages are printed on STDERR rather than STDOUT.

The return code is non-zero when the argument test fails.
Good Luck,
Bill


FishMonger
Veteran / Moderator

Jan 14, 2014, 12:08 PM

Post #4 of 11 (2279 views)
Re: [BillKSmith] Opening check for more files [In reply to] Can't Post

Other differences which are probably definitely improvements:

Lexical filehandle

3 arg form of open

OS reason the open call failed


teardrop
Novice


Jan 14, 2014, 3:31 PM

Post #5 of 11 (2274 views)
Re: [FishMonger] Opening check for more files [In reply to] Can't Post

Thank you for the suggestions, I'm coming from C as you can see from my code so I'm not very good with Perl.

open my $fh, '<', $file

Why this way to open a file is better ( using $fh instead of FILE, for instance)?

Should I use this method everytime?


(This post was edited by teardrop on Jan 14, 2014, 3:32 PM)


Laurent_R
Veteran / Moderator

Jan 15, 2014, 11:56 AM

Post #6 of 11 (2247 views)
Re: [teardrop] Opening check for more files [In reply to] Can't Post

Yes, it is better. One reason is that using a lexical filehandle (my $fh) instead of a bareword filehandle (FH) is that it is much easier to pass it to a subroutine. Separating the open mode argument from the file name is also better because it is cleaner and easier to understand. There are some additional advantages, but these two are sufficient to make this method more recommendable.


teardrop
Novice


Jan 15, 2014, 4:45 PM

Post #7 of 11 (2231 views)
Re: [Laurent_R] Opening check for more files [In reply to] Can't Post

Now I see.
I was trying to do some "silly" exercises but I found a strange behaviour that I can't understand:

Why this one print a lot of GLOB(0xe481a0) in the terminal where I run the script.

Code
#!/usr/bin/perl 
use strict;
use warnings;

open my $Fp,'<',$ARGV[0] or die "$ARGV[0]: $!\n";
my @array=<$Fp>;
my $path="/home/sergio/prova.txt";
open my $Fh, '>', $path or die "$path: $!\n";
foreach ( @array)
{
print $Fh unless (/word/gi);
}
close($Fp) or warn "$ARGV[0]: $!\n";
close($Fh) or warn "$path: $!\n";


and this one work as I expect?


Code
#!/usr/bin/perl 
use strict;
use warnings;

open my $Fp,'<',$ARGV[0] or die "$ARGV[0]: $!\n";
my @array=<$Fp>;
my $path="/home/sergio/prova.txt";
open FILE, '>', $path or die "$path: $!\n";
foreach ( @array)
{
print FILE unless (/word/gi);
}
close($Fp) or warn "$ARGV[0]: $!\n";
close(FILE) or warn "$path: $!\n";



Kenosis
User

Jan 15, 2014, 7:09 PM

Post #8 of 11 (2220 views)
Re: [teardrop] Opening check for more files [In reply to] Can't Post

Because the perl interpreter doesn't recognize the lexical $Fh as a file handle within the context of your print statement, so it stringifies it, producing GLOB()s.

To show this, you can send both scripts to B::Deparse, using the following invocation:

Code
perl -MO=Deparse,-p script.pl

Here's your first script after doing this:

Code
use warnings; 
use strict 'refs';
(open(my $Fp, '<', $ARGV[0]) or die("$ARGV[0]: $!\n"));
(my(@array) = <$Fp>);
(my $path = '/home/sergio/prova.txt');
(open(my $Fh, '>', $path) or die("${path}: $!\n"));
foreach $_ (@array) {
(/word/gi or print($Fh));
}
(close($Fp) or warn("$ARGV[0]: $!\n"));
(close($Fh) or warn("${path}: $!\n"));
temp2.pl syntax OK

Now, your second script:

Code
use warnings; 
use strict 'refs';
(open(my $Fp, '<', $ARGV[0]) or die("$ARGV[0]: $!\n"));
(my(@array) = <$Fp>);
(my $path = '/home/sergio/prova.txt');
(open(FILE, '>', $path) or die("${path}: $!\n"));
foreach $_ (@array) {
(/word/gi or print(FILE $_));
}
(close($Fp) or warn("$ARGV[0]: $!\n"));
(close(FILE) or warn("${path}: $!\n"));
temp2.pl syntax OK

Notice your first's:

Code
 (/word/gi or print($Fh));

compared to your second's:

Code
(/word/gi or print(FILE $_));

With the bareword file handle, perl (the interpreter) 'knows' to (implicitly) print the default scalar $_ to it within the context you've provided.


(This post was edited by Kenosis on Jan 15, 2014, 7:09 PM)


teardrop
Novice


Jan 15, 2014, 8:32 PM

Post #9 of 11 (2213 views)
Re: [Kenosis] Opening check for more files [In reply to] Can't Post

Really thanks to everybody, now I completely solved the problem.
I didn't know about B::Deparse, but it seems a very useful tool to understand how Perl really works.


Kenosis
User

Jan 15, 2014, 9:35 PM

Post #10 of 11 (2209 views)
Re: [teardrop] Opening check for more files [In reply to] Can't Post

One last thought...

You can let Perl handle the file i/o by doing this:

Code
use strict; 
use warnings;

while (<>) {
print unless /word/i;
}

Usage: perl script.pl inFile [>outFile]

The last, optional parameter directs output to a file. Note, also, that a global match isn't necessary: no printing if word occurs just once.


teardrop
Novice


Jan 16, 2014, 10:58 AM

Post #11 of 11 (2196 views)
Re: [Kenosis] Opening check for more files [In reply to] Can't Post

Wow, now I truly understand the meaning of TMTOWTDI.


(This post was edited by teardrop on Jan 16, 2014, 10:59 AM)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives