4.3. open() for Command Execution

The open command can be used for command execution. By prefixing the filename with a pipe (|), the rest of it is interpreted as a command invocation, which accepts standard input by printing to the filehandle, and is executed after the filehandle is closed. If the last character is a pipe, then the command is executed and its standard output is fed into the filehandle where it can be read using Perl's file input mechanisms.

Here are some examples:

#!/usr/bin/perl

use strict;
use warnings;

open my $in, "/sbin/ifconfig |";

my (@addrs);

while (my $line = <$in>)
{
    if ($line =~ /inet addr:((\d+\.)+\d)/)
    {
        push @addrs, $1;
    }
}
close($in);

print "You have the following addresses: \n", join("\n",@addrs), "\n";

#!/usr/bin/perl

use strict;
use warnings;

# Send an E-mail to myself
# Note: this is just an example - there are modules to do this on CPAN.

open MAIL, "|/usr/sbin/sendmail shlomif\@shlomifish.org";
print MAIL "To: Shlomi Fish <shlomif\@shlomifish.org>\n";
print MAIL "From: Shlomi Fish <shlomif\@shlomifish.org>\n";
print MAIL "\n";
print MAIL "Hello there, moi!\n";
close(MAIL);

Pipe to @args

Recent versions of Perl also have a syntax that allows opening a process for input or output using its command line arguments. These are:

open my $print_to_process, "|-", $cmd, @args;
print {$print_to_process} ...;

and:

open my $read_from_process, "-|", $cmd, @args;
while (my $line = <$read_from_process>)
{
.
.
.
}

Doing something like open my $print_to_process, "|-", "sendmail", $to_address; is safer than doing: open my $print_to_process, "|-", "sendmail $to_address"; Because a malicious person may put some offending shell characters in $to_address and end up with something like:

sendmail ; rm -fr $HOME

Written by Shlomi Fish