$ myprogram file1 file2 file3
$ myprogram < inputfile
$ myprogram > outputfile
$ myprogram >> outputfile
$ myprogram | otherprogram
$ otherprogram | myprogram
And here are some more advanced examples:
$ otherprogram | myprogram f1 - f2
$ otherprogram 2>&1 | myprogram -
$ myprogram <&3
$ myprogram >&4
Programmers accustomed to constructs like those above can take comfort in learning that Perl directly supports these familiar constructs using virtually the same syntax as the shell.
For example:
open(INFO, "datafile") || die("can't open datafile: $!");
open(INFO, "< datafile") || die("can't open datafile: $!");
open(RESULTS,"> runstats") || die("can't open runstats: $!");
open(LOG, ">> logfile ") || die("can't open logfile: $!");
If you prefer the low-punctuation version, you could write that this way:
open INFO, "< datafile" or die "can't open datafile: $!";
open RESULTS,"> runstats" or die "can't open runstats: $!";
open LOG, ">> logfile " or die "can't open logfile: $!";
A few things to notice. First, the leading less-than is optional. If omitted, Perl assumes that you want to open the file for reading.
Note also that the first example uses the "||" logical operator, and the second uses "or", which has lower precedence. Using "||" in the latter examples would effectively mean
open INFO, ( "< datafile" || die "can't open datafile: $!" );
which is definitely not what you want.
The other important thing to notice is that, just as in the shell, any whitespace before or after the filename is ignored. This is good, because you wouldn't want these to do different things:
open INFO, "<datafile"
open INFO, "< datafile"
open INFO, "< datafile"
Ignoring surrounding whitespace also helps for when you read a filename in from a different file, and forget to trim it before opening:
$filename = <INFO>; # oops, \n still there
open(EXTRA, "< $filename") || die "can't open $filename: $!";
This is not a bug, but a feature. Because "open" mimics the shell in its style of using redirection arrows to specify how to open the file, it also does so with respect to extra whitespace around the filename itself as well. For accessing files with naughty names, see ``Dispelling the Dweomer''.
There is also a 3-argument version of "open", which lets you put the special redirection characters into their own argument:
open( INFO, ">", $datafile ) || die "Can't create $datafile: $!";
In this case, the filename to open is the actual string in $datafile, so you don't have to worry about $datafile containing characters that might influence the open mode, or whitespace at the beginning of the filename that would be absorbed in the 2-argument version. Also, any reduction of unnecessary string interpolation is a good thing.
open( my $in, $infile ) or die "Couldn't read $infile: $!";
while ( <$in> ) {
# do something with $_
}
close $in;
Indirect filehandles make namespace management easier. Since filehandles are global to the current package, two subroutines trying to open "INFILE" will clash. With two functions opening indirect filehandles like "my $infile", there's no clash and no need to worry about future conflicts.
Another convenient behavior is that an indirect filehandle automatically closes when it goes out of scope or when you undefine it:
sub firstline {
open( my $in, shift ) && return scalar <$in>;
# no close() required
}
If the leading character is a pipe symbol, "open" starts up a new command and opens a write-only filehandle leading into that command. This lets you write into that handle and have what you write show up on that command's standard input. For example:
open(PRINTER, "| lpr -Plp1") || die "can't run lpr: $!";
print PRINTER "stuff\n";
close(PRINTER) || die "can't close lpr: $!";
If the trailing character is a pipe, you start up a new command and open a read-only filehandle leading out of that command. This lets whatever that command writes to its standard output show up on your handle for reading. For example:
open(NET, "netstat -i -n |") || die "can't fork netstat: $!";
while (<NET>) { } # do something with input
close(NET) || die "can't close netstat: $!";
What happens if you try to open a pipe to or from a non-existent command? If possible, Perl will detect the failure and set $! as usual. But if the command contains special shell characters, such as ">" or "*", called 'metacharacters', Perl does not execute the command directly. Instead, Perl runs the shell, which then tries to run the command. This means that it's the shell that gets the error indication. In such a case, the "open" call will only indicate failure if Perl can't even run the shell. See ``How can I capture STDERR from an external command?'' in perlfaq8 to see how to cope with this. There's also an explanation in perlipc.
If you would like to open a bidirectional pipe, the IPC::Open2 library will handle this for you. Check out ``Bidirectional Communication with Another Process'' in perlipc