You think that if they teach you Perl, they will use modern Perl syntax. Please do not take it personally. In the end, this is how you studied. However, you should be aware of the new Perl programming style, as it helps eliminate all sorts of programming errors and makes code easier to understand.
- Use pragmas
use strict; and use warnings; . The warning pragma replaces the need for the -w flag on the command line. It is actually more flexible and better. For example, I can turn off special warnings when I know that they will be a problem. Pragma use strict; requires me to declare my variables with both mine and ours. (NOTE: Do not declare Perl built-in variables.) In 99% of cases you will use mine. These variables are called lexically encompassed, but you can think of them as true local variables. Vocabulary-oriented variables have no value outside their scope. For example, if you declare a variable using my inside a while loop, that variable will disappear after the loop exits. - Use three parameter syntaxes for the
open statement . In the example below, I use three parameter syntaxes. That way, if the file is named >myfile , I can read it. - ** Use locally defined file descriptors. Note that I'm using
my $file_1_fh instead of just FILE_1_HANDLE. The old way is FILE_1_HANDLE all over the world, and it is very difficult to pass a file descriptor to a function. Using lexically processed files works great. - Use
or and and instead of || and && . They are easier to understand, and their priority for operators is better. They are likely to cause no problems. - Always check if your
open statement works : you need to make sure that your open statement actually opened the file. Or use the pragma use autodie; , which will kill your program if open instructions fail (this is probably what you want to do anyway.
And here is your program:
#! /usr/bin/env perl # use strict; use warnings; use autodie; open my $file_1, "<", shift; open my $file_2, "<", shift; open my $output_fh, ">", shift; for (;;) { my $line_1 = <$file_1>; my $line_2 = <$file_2>; last if not defined $line_1 and not defined $line_2; no warnings qw(uninitialized); print {$output_fh} $line_1 . $line_2; use warnings; }
In the above example, I read both files, even if they are empty. If there is nothing to read, then $line_1 or $line_2 simply undefined. After I read, I check if $line_1 and $line_2 undefined. If so, I use last to complete my loop.
Since my file descriptor is a scalar variable, I like to put it in braces, so people know this file descriptor, not the variable I want to print. I do not need this, but it improves clarity.
Pay attention to no warnings qw(uninitialized); . This will disable the uninitialized warning that I will receive. I know that either $line_1 or $line_3 can be uninitialized, so I do not want this warning. I will bring it back below my print application because it is a valuable warning.
Here is another way to do this for loop:
while ( 1 ) { my $line_1 = <$file_1>; my $line_2 = <$file_2>; last if not defined $line_1 and not defined $line_2; print {$output_fh} $line_1 if defined $line_1; print {$output_fh} $line_2 if defined $line_2; }
An infinite loop is a while loop instead of a for loop. Some people don't like the C style in the for loop and have banned it from coding practice. That way, if you have an infinite loop, you use while ( 1 ) { . For me, perhaps because I came from the background of C, for (;;) { means an infinite loop, while while ( 1 ) { takes a few extra milliseconds to digest.
In addition, I check if $line_1 or $line_2 before I print them. I think this is better than using no warning and warning , but I need two separate print statements instead of combining them into one.