问题
A simple program with while( <> )
handles files given as arguments (./program 1.file 2.file 3.file
) and standard input of Unix systems.
I think it concatenates them together in one file and work is line by line. The problem is, how do I know that I'm working with the first file? And then with the second one.
For a simple example, I want to print the file's content in one line.
while( <> ){
print "\n" if (it's the second file already);
print $_;
}
回答1:
The diamond operator does not concatenate the files, it just opens and reads them consecutively. How you control this depends on how you need it controlled. A simple way to check when we have read the last line of a file is to use eof
:
while (<>) {
chomp; # remove newline
print; # print the line
print "\n" if eof; # at end of file, print a newline
}
You can also consider a counter to keep track of which file in order you are processing
$counter++ if eof;
Note that this count will increase by one at the last line of the file, so do not use it prematurely.
If you want to keep track of line number $.
in the current file handle, you can close
the ARGV file handle to reset this counter:
while (<>) {
print "line $. : ", $_;
close ARGV if eof;
}
回答2:
The <>
is a special case of the readline operator. It usually takes a filehandle: <$fh>
.
If the filehandle is left out, then the the magic ARGV
filehandle is used.
If no command line arguments are given, then ARGV
is STDIN
. If command line arguments are given, then ARGV
will be open
ed to each of those in turn. This is similar to
# Pseudocode
while ($ARGV = shift @ARGV) {
open ARGV, $ARGV or do{
warn "Can't open $ARGV: $!";
next;
};
while (<ARGV>) {
...; # your code
}
}
The $ARGV
variable is real, and holds the filename of the file currently opened.
Please be aware that the two-arg form of open
(which is probably used here behind the scenes), is quite unsafe. The filename rm -rf * |
may not do what you want.
回答3:
The name of the current file for <>
is contained in special $ARGV
variable.
You can cross-match your list of files from @ARGV
parameter array with current file name to get the file's position in the list. Assuming the only parameters you expect are filenames, you can simply do:
my %filename_positions = map { ( $ARGV[$_] => $_ ) } 0..$#ARGV;
while (<>) {
my $file_number = $filename_positions{$ARGV};
#... if ($file_number == 0) { #first file
}
来源:https://stackoverflow.com/questions/14922272/perl-while-file-handling