tags:

views:

247

answers:

6

When executing a command on the command-line from Perl, is there a way to store that result as a variable in Perl?

my $command    = "cat $input_file | uniq -d | wc -l";
my $result     = system($command);

$result always turns out to be 0.

+3  A: 

You can use the Perl back-ticks to run a shell command, and save the result in an array.

my @results = `$command`;

To get just a single result from the shell command, you can store it in a scalar variable:

my $result = `$command`;

If you are expecting back multiple lines of output, it's easier to use an array, but if you're just expecting back one line, it's better to use scalar.

(something like that, my perl is rusty)

Andy White
+9  A: 

Use "backticks":

my $command    = "cat $input_file | uniq -d | wc -l";
my $result     = `$command`;

And if interested in the exit code you can capture it with:

my $retcode = $?;

right after making the external call.

exhuma
A: 

I'm assuming this a 'contrived' example, because this is equivalent: 'uniq -d $input_file | wc -l'.

In almost all my experience, the only reason for putting the results in to a perl variable, is to parse the later. In that case, I use the following pattern:

$last = undef;
$lc = 0;
open(FN, "$input_file");
while (<FN>) {
   # any other parsing of the current line
   $lc++ if ($last eq $_);
   $last = $_;
}
close(FN);
print "$lc\n";

This also has the added advantages:

  • no fork for shell, cat, uniq, and wc
  • faster
  • parse and collect the desired input
codeDr
open() or die($!);
Dominic Mitchell
+6  A: 

From perlfaq8:


Why can't I get the output of a command with system()?

You're confusing the purpose of system() and backticks (``). `system()` runs a command and returns exit status information (as a 16 bit value: the low 7 bits are the signal the process died from, if any, and the high 8 bits are the actual exit value). Backticks () run a command and return what it sent to STDOUT.

$exit_status   = system("mail-users");
$output_string = `ls`;
brian d foy
+1  A: 

You can use backticks, as others have suggested. That's fine if you trust whatever variables you're using to build your command.

For more flexibility, you can open the command as a pipe and read from that as you would a file. This is particularly useful when you want to pass variables as command line arguments to the program and you don't trust their source to be free of shell escape characters, as open in recent Perl (>= 5.8) has the capacity to invoke a program from an argument list. So you can do the following:

open(FILEHANDLE, '-|', 'uniq', 'some-file.txt') or die "Cannot fork: $!\n";
while (<FILEHANDLE>) {
    # process a line from $_
}
close FILEHANDLE or die "child error: $!\n";
Michael E
+1  A: 

IPC::System::Simple provides the 'capture' command which provides a safe, portable alternative to backticks. It (and other commands from this module) are highly recommended.

megamic
thanks for pointing out that module.
glenn jackman