Contents
9. Loops and I/O
Example: Command Line Values and Iterative Loops
print "$#ARGV is the subscript of the ",
"last command argument.\n";
# Iterate on numeric subscript 0 to $#ARGV:
for ($i=0; $i <= $#ARGV; $i++) {
print "Argument $i is $ARGV[$i].\n";
}
# A variation on the preceding loop:
foreach $item (@ARGV) {
print "The word is: $item.\n";
}
# A similar variation, using the
# "Default Scalar Variable" $_ :
foreach (@ARGV) {
print "Say: $_.\n";
}
Demonstration: > perl example5.pl Gooood morning, Columbia!
2 is the subscript of the last command argument.
Argument 0 is Gooood.
Argument 1 is morning,.
Argument 2 is Columbia!.
The word is: Gooood.
The word is: morning,.
The word is: Columbia!.
Say: Gooood.
Say: morning,.
Say: Columbia!.
Example: Standard I/O
print STDOUT "Tell me something: ";
while ($input = <STDIN>) {
print STDOUT "You said, quote: $input endquote\n";
chop $input;
print STDOUT "Without the newline: $input endquote\n";
if ($input eq '') { print STDERR "Null input!\n"; }
print STDOUT "Tell me more, or ^D to end:\n";
}
print STDOUT "That's all!\n";
Note 1: The
while
statement's condition is an assignment statement: assign the next record from
standard input to the variable $input. On end of file, this will assign not a
null value but an "undefined" value. An undefined value in the context of a
condition evaluates to "false". So the "
while ($input =
<STDIN>)
" does three things: gets a record, assigns it to $input,
and tests whether $input is undefined. In other contexts, Perl treats an
undefined variable as null or zero. Thus, if
$i
is not initialized,
$i++
sets
$i
to 1. Perl Paradox Number Three:
Side
effects can yield an elegant face or a pain in the rear.
Note 2: Data records are by default terminated by a newline character "\n"
which in the above example is included as the last character of variable $input.
The "chop" function removes the last character of its argument. Perl 5
introduces a "chomp" function that removes the last characters of a variable
only if they are the currently defined end-of-record sequence, which is defined
in the special variable $/.
Demonstration:
> perl example6.pl
Tell me something: I'm warm.
You said, quote: I'm warm.
endquote
Without the newline: I'm warm. endquote
Tell me more, or ^D to end:
Can I have some water?
You said, quote: Can I have some water?
endquote
Without the newline: Can I have some water? endquote
Tell me more, or ^D to end:
You said, quote:
endquote
Without the newline: endquote
Null input!
Tell me more, or ^D to end:
^D
That's all!
Example: Perls, A Perl Shell, Calculator, & Learning Tool
#!/usr/local/bin/perl
for (;;) {
print '(',join(', ',@ReSuLt),') ?';
last unless $InPuT = <STDIN>;
$? = ''; $@ = ''; $! = '';
@ReSuLt = eval $InPuT;
if ($?) { print 'status=',$?,' ' }
if ($@) { print 'errmsg=',$@,' ' }
if ($!) { print 'errno=',$!+0,': ',$!,' ' }
}
This reads a line from the terminal and executes it as a Perl
program. The "for (;;) {...}" makes an endless loop. The "last unless" line
might be equivalently specified:
$InPuT = <STDIN>; # Get line from standard input.
if (! defined($InPuT)) {last;} # If no line, leave the loop.
The
"eval" function in Perl evaluates a string as a Perl program. "$@" is the Perl
error message from the last "eval" or "do".
Demonstration:
perls
() ?Howdy
(Howdy) ?2+5
(7) ?sqrt(2)
(1.4142135623730951) ?$x
() ?$x = sqrt(2)
(1.4142135623730951) ?$x + 5
(6.4142135623730949) ?1/0
errmsg=Illegal division by constant zero in file (eval) at line 2, next 2 tokens "0;"
() ?system 'date'
Fri Sep 27 10:02:43 CDT 1996
(0) ?$x = `date`
(Fri Sep 27 10:02:52 CDT 1996
) ?chop $x
(
) ?$x
(Fri Sep 27 10:02:52 CDT 1996) ?@y = split(/ /,$x)
(Fri, Sep, 27, 10:02:52, CDT, 1996) ?@y[1,2,5]
(Sep, 27, 1996) ?localtime()
(37, 4, 10, 27, 8, 96, 5, 270, 1) ?
() ?foreach (1..10) {print sqrt(),' '}
1 1.4142135623730951 1.7320508075688772 2 2.2360679774997898
2.4494897427831779 2.6457513110645907 2.8284271247461903 3 3.1622776601683795
() ?exit
Example: File I/O
#!/usr/local/bin/perl
# Function: Reverse each line of a file
# 1: Get command line values:
if ($#ARGV !=1) {
die "Usage: $0 inputfile outputfile\n";
}
($infile,$outfile) = @ARGV;
if (! -r $infile) {
die "Can't read input $infile\n";
}
if (! -f $infile) {
die "Input $infile is not a plain file\n";
}
# 2: Validate files
# Or statements "||" short-circuit, so that if an early part
# evaluates as true, Perl doesn't bother to evaluate the rest.
# Here, if the file opens successfully, we don't abort:
open(INPUT,"<$infile") ||
die "Can't input $infile $!";
if ( -e $outfile) {
print STDERR "Output file $outfile exists!\n";
until ($ans eq 'r' || $ans eq 'a' || $ans eq 'e' ) {
print STDERR "replace, append, or exit? ";
$ans = getc(STDIN);
}
if ($ans eq 'e') {exit}
}
if ($ans eq 'a') {$mode='>>'}
else {$mode='>'}
open(OUTPUT,"$mode$outfile") ||
die "Can't output $outfile $!";
# 3: Read input, reverse each line, output it.
while (<INPUT>) {
chop $_;
$_ = reverse $_;
print OUTPUT $_,"\n";
}
# 4: Done!
close INPUT,OUTPUT;
exit;