Elias has asked for the wisdom of the Perl Monks concerning the following question:
Of each dropped file, I would like to pass the filename first, and then the data, to an array. I have tried this:
foreach my $file (@ARGV) {
push @data, substr($file, -12, 12);
while (<>) {
push (@data=>$_);
}
}
However, it does not work: Only the first filename is pushed onto the array, followed by all the data in the files. Should I make a filehandle for each $file in @ARGV and loop the while statement over these filehandles? Is there another, more elegant solution?
Re (tilly) 1: How do I read the files in @ARGV one by one
by tilly (Archbishop) on Mar 19, 2001 at 21:30 UTC
|
$data{$_} = [] foreach @ARGV;
while (<>) {
push @{$data{$ARGV}}, $_;
}
The purpose of the first line is to make sure that files which are empty are included in your hash.
| [reply] [d/l] |
Re: How do I read the files in @ARGV one by one
by merlyn (Sage) on Mar 19, 2001 at 21:48 UTC
|
@ARGV = $_, push @data, $_, <> for @{[@ARGV]};
Hmm. There was some other clever trick to dup a list too, but I can't recall now.
-- Randal L. Schwartz, Perl hacker
update:
Yeah, it's
@ARGV = $_, push @data, $_, <> for map $_, @ARGV;
| [reply] [d/l] [select] |
Re: How do I read the files in @ARGV one by one
by Masem (Monsignor) on Mar 19, 2001 at 20:54 UTC
|
Right now, you have no file handles to those data files to speak of, so it's odd how you are getting even that data. The way you want to do it is:
foreach my $file (@ARGV) {
if ( -e $file ) { # double check existence
push @data, $file;
open FILE , '<'.$file or die $!;
while( <FILE> ) { push @data, $_; }
close FILE;
}
}
Dr. Michael K. Neylon - mneylon-pm@masemware.com
||
"You've left the lens cap of your mind on again, Pinky" - The Brain
| [reply] [d/l] |
|
It's not odd because he's using the <> operator, which returns all the data from all the files listed in @ARGV, all in one pass, line by line. It doesn't let you break it up by file, though.
--isotope
http://www.skylab.org/~isotope/
| [reply] |
(jeffa) Re: How do I read the files in @ARGV one by one
by jeffa (Bishop) on Mar 19, 2001 at 20:58 UTC
|
Personally, I prefer to just open a filehandle:
use IO::File;
my %files;
foreach my $name (@ARGV) {
my $file = IO::File->new($name) or next; # print error message her
+e, etc.
my @lines = <$file>;
$files{$name} = \@lines;
$file->close;
}
Jeff
R-R-R--R-R-R--R-R-R--R-R-R--R-R-R--
L-L--L-L--L-L--L-L--L-L--L-L--L-L--
| [reply] [d/l] |
Re: How do I read the files in @ARGV one by one
by bjelli (Pilgrim) on Mar 19, 2001 at 21:39 UTC
|
The trouble with your code is that <> does
advanced magic: it reads in all the files
on the command line line by line. You can
find out which file you are reading right now
by looking at $ARGV.
So for your little problem,
you could remember what $ARGV was when you
last read a line and check if $ARGV has changed:
my $OLDARGV;
while (<>) {
push(@data, $ARGV) if $ARGV ne $OLDARGV;
push(@data, $_);
$OLDARGV=$ARGV;
}
But I admit that Masems code is
probably easier to figure out.
--
Brigitte 'I never met a chocolate I didnt like' Jellinek
http://www.horus.com/~bjelli/ http://perlwelt.horus.at | [reply] [d/l] |
Re: How do I read the files in @ARGV one by one
by merlyn (Sage) on Mar 19, 2001 at 23:59 UTC
|
OK, one other twisted way:
my @data = do {
my @copy = @ARGV;
local $/;
map { shift @copy, map /(.*\n?)/g, $_ } <>;
};
-- Randal L. Schwartz, Perl hacker | [reply] [d/l] |
|
Make sure you don't do what I just did:
my @ARGV = $file;
The my creates a new, local @ARGV which is not what you want. Doh!
| [reply] [d/l] [select] |
Re: How do I read the files in @ARGV one by one
by busunsl (Vicar) on Mar 19, 2001 at 20:55 UTC
|
Have a look at 'eof', it will tell you when a file ends.
perldoc -f eof
| [reply] |
|
my @data;
foreach my $file (@ARGV) {
push @data, substr( $file, -12, 12 );
local( *ARGV );
@ARGV= ($file);
push( @data, <> );
}
-
tye
(but my friends call me "Tye") | [reply] [d/l] |
Re: How do I read the files in @ARGV one by one
by orbital (Scribe) on Mar 19, 2001 at 21:23 UTC
|
You can also check into Getopt::Std or Getopt::Long, both of these modules give you more control over the command line. here is an example usage:
use Getopt::Long;
Configure( \%Config );
if( $Config{help} ){ Syntax(); exit();}
....Code Goes Here.....
sub Configure {
my( $Config ) = @_;
my $Result = 0;
Getopt::Long::Configure( "prefix_pattern=(-|\/)" );
$Result = GetOptions( $Config,
qw(
del|d=i
length|l=i
path|p=s
first|f=s
reports|r=i
help|?|h
) );
if (! scalar $Config->{line}) { $Config->{line}=132;}
if (! scalar $Config->{reports}) { $Config->{reports}=1;}
if (! exists $Config->{path}) { Syntax(); exit; }
if (! exists $Config->{first}) { Syntax(); exit; }
if (exists $Config->{del}) { Delete(); }
$stream = $Config->{line};
$rptpag = $Config->{reports};
$dir = $Config->{path};
$firstln = $Config->{first};
}
sub Syntax
{
print <<EOT;
ansi.pl
-------
Used for Adding/Removing ANSI printer control characters.
Syntax:
ansi.pl [-l length] [-p path] [-f first] [-r reports] [-d del]
-l..........Defines length of each line in the files. [default
+=132]
-p..........Specifies the directory path to process. [must be
+defined]
(Directory must end with a \\)
-f..........Defines the first line of a report. [must be defin
+ed]
-r..........Set the number of reports per page. [default=1]
-d..........Deletes defined number of characters from beginnin
+g of
each line. [optional]
-h..........This help screen.
*(looks for all *.dat in specified directory, saves original t
+o *.bak)
EOT
}
| [reply] [d/l] |
|
|