Perl pipe - Reading from a pipeline with Perl

Perl pipeline FAQ: How can I read output from a shell command pipeline (pipe) in a Perl script?

One of the great things about Perl is that it's very easy to run operating system commands, and read the output of those commands. Perl makes this process very easy and natural - it's just like reading data from a file. In this article we'll demonstrate the process of running external commands from within Perl, and then reading the output of those commands.

Perl shell command pipeline example - reading the date

Here's a simple example of running a system command (shell command) and reading the output of the command in your Perl script. The Unix date command prints the system date and time. Running it at the command line, you get output that looks something like this:

Sun Jul 12 16:55:51 EDT 1998

To run the date command from a Perl program, and read the output of the command, all you need are a few lines of code like this:

open(DATE, "date|");
$theDate = <DATE>;
close(DATE);

Listing 1 (above): A short code snippet that runs the external date command, and then read it's output into the variable $theDate.

This Perl example runs the Unix/Linux date command, and then reads from the command pipeline. I like to think of this as being just like opening up a file for read access.

Next, the output of the date command is read into the Perl variable $theDate. Here we're just using the line reading operator <> to read from the pipeline. Then when we're done reading from the pipe we simply close it.

A more complicated Perl pipe example - reading the output of the ps command

To make this a little more complicated, let's assume that we want to read the output of the ps -f command in a Perl script. Typical output of this command looks like this:

     UID   PID  PPID  CLS PRI  C    STIME TTY      TIME COMD 
    root  8853  8842   TS  70  0 16:55:42 pts007   0:00 ksh 
    root  8875  8853       59  0 17:08:35 pts007   0:00 ps -f
    root  8842  8840   TS  70  0 16:55:22 pts007   0:00 -sh 

Listing 2 (above): Sample output of the Unix ps -f command.

Reading this command output in a Perl script is a little more difficult because there are multiple lines of output to contend with, but this is easily taken care of by using a while loop to handle the reading. Listing 3 shows a code snippet that (a) runs the ps -f command, and (b) reads the output of the command:

open(PS_F, "ps -f|");

while (<PS_F>) {
  ($uid,$pid,$ppid,$restOfLine) = split;
  # do whatever I want with the variables here ...
}

close(PS_F);

Listing 3 (above): A short code snippet that runs the external ps -f command, and then reads it's output with the help of a while loop.

In Listing 3 we do the same thing we did in Listing 1 - we run an external command, and then read from it. However, in this case we know that we're going to get multiple lines of output from the command, so we read from the pipeline using a while loop.

After setting up the while loop, we take our example a step farther by reading the output into four variables: $user, $pid, $ppid, and $restOfLine. Here I'm assuming that I'm only really interested in the first three columns of output, and the other columns are of no concern. This is easily accomplished with Perl's split function.

Note that in this example I'm taking advantage of a few of Perl's shortcuts. The output of the ps -f command is read automagically read into the special variable $_. (This is a convenience feature of Perl.) Then, because the output is stored in the $_ variable, I can just write split instead of "split($_);".

After reading the data into these variables, I can do whatever I want with the information in the loop. This part I leave to your imagination - and your application.

Reader Follow-Up Comments:

From Dave Cross and others:

Things like your date example are easier using backticks:

$theDate = `date`; 

This can also be used for the ps example.

You also imply that just using split is the same as split($_) when it's really split(/\s+/,$_).