For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > April 2007 > cat (.sh) in Perl









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author cat (.sh) in Perl
Yitzle

2007-04-25, 6:58 pm

`cat m.top.html m.mid.html m.arc.html m.bot.html > blah`
How can this be done without a system call?

Here's my first guess:
@doc = ();
for (qw/m.top.html m.mid.html m.arc.html m.bot.html/) {
open $FILE,"<","$root/$_";
my @tmp = <$FILE>;
@doc = (@doc,@tmp);
close $FILE;
}
open $FILE,">","blah";
print $FILE $_ foreach(@doc);
close $FILE;

Is there something I'm missing?

Thanks!
Rob Dixon

2007-04-25, 9:58 pm

yitzle wrote:
>
> `cat m.top.html m.mid.html m.arc.html m.bot.html > blah`
> How can this be done without a system call?
>
> Here's my first guess:
> @doc = ();
> for (qw/m.top.html m.mid.html m.arc.html m.bot.html/) {
> open $FILE,"<","$root/$_";
> my @tmp = <$FILE>;
> @doc = (@doc,@tmp);
> close $FILE;
> }
> open $FILE,">","blah";
> print $FILE $_ foreach(@doc);
> close $FILE;
>
> Is there something I'm missing?


I would do it like this:

use strict;
use warnings;

open my $out, '>', 'blah' or die $!;

local @ARGV = qw/m.top.html m.mid.html m.arc.html m.bot.html/;

while (<> ) {
print $out, $_;
}

HTH,

Rob
John W. Krahn

2007-04-25, 9:58 pm

yitzle wrote:
> `cat m.top.html m.mid.html m.arc.html m.bot.html > blah`
> How can this be done without a system call?
>
> Here's my first guess:


use warnings;
use strict;

> @doc = ();


my @doc;

> for (qw/m.top.html m.mid.html m.arc.html m.bot.html/) {
> open $FILE,"<","$root/$_";


Where is $root defined and what does it contain? You should *ALWAYS* verify
that the file opened correctly.

open my $FILE, '<', "$root/$_" or die "Cannot open '$root/$_' $!";

> my @tmp = <$FILE>;
> @doc = (@doc,@tmp);


push @doc, <$FILE>;

> close $FILE;
> }
> open $FILE,">","blah";


You should *ALWAYS* verify that the file opened correctly.

open my $FILE, '>', 'blah' or die "Cannot open 'blah' $!";

> print $FILE $_ foreach(@doc);


Or just:

print $FILE @doc;

> close $FILE;
>
> Is there something I'm missing?


You could use the magical <> operator:

use warnings;
use strict;

@ARGV = qw/ m.top.html m.mid.html m.arc.html m.bot.html /;

open my $FILE, '>', 'blah' or die "Cannot open 'blah' $!";

print $FILE $_ while <>;

__END__




John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
Seanie

2007-04-25, 9:58 pm

yitzle wrote:
> `cat m.top.html m.mid.html m.arc.html m.bot.html > blah`
> How can this be done without a system call?


As a general rule, if your script contains 'system()' anywhere in it, you've
done it wrong. This is especially true for simple file operations such as
the above, and for anything else CPAN has yet to fail me. I can't remember
the last time I was forced to shell out to get something done.

> Here's my first guess:
> @doc = ();
> for (qw/m.top.html m.mid.html m.arc.html m.bot.html/) {
> open $FILE,"<","$root/$_";
> my @tmp = <$FILE>;
> @doc = (@doc,@tmp);
> close $FILE;
> }
> open $FILE,">","blah";
> print $FILE $_ foreach(@doc);
> close $FILE;
>
> Is there something I'm missing?


Quite a lot, yes.

Always use the strict and warnings pragmas, no exceptions, and test to ensure
operations on files, sockets etc have worked before moving on.
You don't need to loop your file contents in, and then loop them back out
again separately later; one for loop will suffice for both.
Your syntax for the open() statements is a bit dodgy too :-)

Here's a fairly verbose chunk of code that ought to do what you want:

use strict;
use warnings;
open OUTFILE, ">blah" or die "error creating output file\n";
for my $infile (qw|m.top.html m.mid.html m.arc.html m.bot.html|){
die "$infile not found" unless -r "$root/$infile"; # or use next to skip it
open INFILE, "<$root/$infile" or die "error opening input file\n";
print OUTFILE while (<INFILE> );
close INFILE;
}
close OUTFILE;

Keep in mind that there are plenty of other ways of doing this, some terser
than others. You can even do this:

perl -pe m.top.html m.mid.html m.arc.html m.bot.html > blah

.....which is Perl doing a very convincing cat impression.

--
Seanie@wdcc.org.uk [pgp: 8A8FA6DE]

John W. Krahn

2007-04-25, 9:58 pm

Seanie wrote:
> yitzle wrote:
>
> As a general rule, if your script contains 'system()' anywhere in it, you've
> done it wrong. This is especially true for simple file operations such as
> the above, and for anything else CPAN has yet to fail me. I can't remember
> the last time I was forced to shell out to get something done.
>
>
> Quite a lot, yes.
>
> Always use the strict and warnings pragmas, no exceptions, and test to ensure
> operations on files, sockets etc have worked before moving on.
> You don't need to loop your file contents in, and then loop them back out
> again separately later; one for loop will suffice for both.
> Your syntax for the open() statements is a bit dodgy too :-)


Perl defines the syntax so you must mean something else? :-)

> Here's a fairly verbose chunk of code that ought to do what you want:
>
> use strict;
> use warnings;
> open OUTFILE, ">blah" or die "error creating output file\n";


You should also include the $! or $^E variable in the error message so you
know *why* it failed.

> for my $infile (qw|m.top.html m.mid.html m.arc.html m.bot.html|){
> die "$infile not found" unless -r "$root/$infile"; # or use next to skip it


$infile could exist and not be readable so the message "$infile not found"
does not accurately describe the problem and if you are logged in as root then
the file is readable reguardless. Also you have a race condition where the
file could be made unreadable between that statement and the next one.

> open INFILE, "<$root/$infile" or die "error opening input file\n";


See above about $! and/or $^E.

> print OUTFILE while (<INFILE> );
> close INFILE;
> }
> close OUTFILE;
>
> Keep in mind that there are plenty of other ways of doing this, some terser
> than others. You can even do this:
>
> perl -pe m.top.html m.mid.html m.arc.html m.bot.html > blah
>
> ....which is Perl doing a very convincing cat impression.


Except that you are saying that 'm.top.html' is a Perl program that perl
should compile and run (which will probably produce a *lot* of error messages.)



John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
Seanie

2007-04-25, 9:58 pm

John W. Krahn wrote:
> Perl defines the syntax so you must mean something else? :-)


As in "too much unnecessary typing and commas and such, which don't really
add clarity", rather than "incorrect"

> You should also include the $! or $^E variable in the error message so you
> know *why* it failed.


Yes yes. I was making the point that file operations should be tested and
throw errors when they barf. Which the OP wasn't doing.

>
> $infile could exist and not be readable so the message "$infile not found"
> does not accurately describe the problem


Ok, granted. s/found/readable/

> and if you are logged in as root then the file is readable reguardless.

Unless it doesn't exist. What's your point?

> Also you have a race condition
> where the file could be made unreadable between that statement and the
> next one.


And could be deleted entirely before (or during) the subsequent read by
another process. Still not sure of your point. I didn't think the OP wanted
a lecture about file locking.

> Except that you are saying that 'm.top.html' is a Perl program that perl
> should compile and run (which will probably produce a *lot* of error
> messages.)


OK, I missed a pair of single quotes after the -pe. I'll give you that one.

--
Seanie@wdcc.org.uk [pgp: 8A8FA6DE]
John W. Krahn

2007-04-25, 9:58 pm

Seanie wrote:
> John W. Krahn wrote:
>
> As in "too much unnecessary typing and commas and such, which don't really
> add clarity", rather than "incorrect"


The OP's open statements:

> open $FILE,"<","$root/$_";
>
> open $FILE,">","blah";


Can you explain where the "too much unnecessary typing and commas and such"
exist in those statements?

[ snip ]

>
> Ok, granted. s/found/readable/
>
> Unless it doesn't exist. What's your point?
>
>
> And could be deleted entirely before (or during) the subsequent read by
> another process. Still not sure of your point. I didn't think the OP wanted
> a lecture about file locking.


I said nothing about locking. I was making the point that the test for
readability is redundant as the die() after open() will catch any existence or
readability problems anyway.



John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
Paul Johnson

2007-04-26, 6:58 pm

On Thu, Apr 26, 2007 at 01:38:02AM +0100, Seanie wrote:

> As a general rule, if your script contains 'system()' anywhere in it, you've
> done it wrong.


I think this is a little strong. Or a little general. Or something.

Sometimes a calling system() is exactly the right thing to do.
Sometimes it isn't. Determining which is which is part of what it takes
to become a good Perl programmer.

--
Paul Johnson - paul@pjcj.net
http://www.pjcj.net
Mcgee

2007-04-28, 5:35 am

http://Pamela-Anderson-in-nylons.in...hp?movie=148803
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com