28

I have a problem with the system function. I want to store the system functions output to a variable.

For example,

system("ls");

Here I want all the file names in the current directory to store in a variable. I know that I can do this by redirecting the output into a file and read from that and store that to a variable. But I want a efficient way than that. Is there any way .

brian d foy
  • 129,424
  • 31
  • 207
  • 592
karthi_ms
  • 5,568
  • 11
  • 38
  • 39

8 Answers8

21

No, you cannot store the values of the ls output , since system always execute the command as a child process , so try with backtick `command` which executes the command in the current process itself!

abubacker
  • 4,638
  • 6
  • 32
  • 35
  • 4
    @abubacker - backticks does execute a child process. – martin clayton Mar 10 '10 at 10:13
  • 5
    Backticks execute the command in a child process and capture its output. If you want to execute the command in the same process, you use `exec` - but it will never return because the original Perl code is no longer running after turning the process over to the other command. – Dave Sherohman Mar 10 '10 at 11:03
  • 1
    How would one go about capturing the output of a command into a variable without showing it on screen? – antred Feb 14 '18 at 12:38
19

The easiest way uses backticks or qx():

my $value = qx(ls);
print $value;

The output is similar to the ls.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • 1
    `echo` is a shell command, the Perl equivalents are called `print` and `say`. – daxim Mar 10 '10 at 11:12
  • That works for ls, but not for the find command, for that i guess its backticks, http://stackoverflow.com/questions/3854651/how-can-i-store-the-result-of-a-system-command-in-a-perl-variable. – john-jones Dec 28 '14 at 10:53
  • Please advise what should be the syntax when the "command" contains some Perl variables, such as `"ffmpeg -v error -i $file.mp4 -f null - 2>&1`. Thanks. – Ωmega Jan 27 '20 at 23:34
10

My answer does not address your problem. However, if you REALLY want to do directory listing, don't call system ls like that. Use opendir(), readdir(), or a while loop.

For example,

while (<*>){
    print $_ ."\n";
}

In fact, if it's not a third-party proprietary program, always try to user Perl's own functions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
9

As abubacker stated, you can use backticks to capture the output of a program into a variable for later use. However, if you also need to check for exceptional return values, or bypass invoking the shell, it's time to bring in a CPAN module, IPC::System::Simple:

use IPC::System::Simple qw(capture);

# Capture output into $result and throw exception on failure
my $result = capture("some_command"); 

This module can be called in a variety of ways, and allows you to customize which error return values are "acceptable", whether to bypass the shell or not, and how to handle grouping of arguments. It also provides a drop-in replacement for system() which adds more error-checking.

Ether
  • 53,118
  • 13
  • 86
  • 159
7

The official Perl documentation for the built-in system function states:

This is not what you want to use to capture the output from a command, for that you should use merely backticks or qx//, as described in "STRING" in perlop.

There are numerous ways to easily access the docs:

  1. At the command line: perldoc -f system
  2. Online at perldoc.perl.org.
  3. Search the web using google.

If you want each directory listing stored into a separate array element, use:

my @entries = qx(ls);
toolic
  • 57,801
  • 17
  • 75
  • 117
2

Use backticks to store output in a variable

$output = `ls`;
serenesat
  • 4,611
  • 10
  • 37
  • 53
1

A quick and simple way to do this is to use qx() specifically for your example:

my $output = qx(ls 2>&1);

The 2>&1 part is to capture both stdout and stderr.

James Oravec
  • 19,579
  • 27
  • 94
  • 160
1

Since it has not been mentioned by other answers yet, you can also use Capture::Tiny to store any arbitrary STDOUT (and/or STDERR) into a variable, including from the system command.

use strict;
use warnings;
use Capture::Tiny 'capture_stdout';
my ($stdout, $return) = capture_stdout { system 'ls' };
# error checking for system return value required here
Grinnz
  • 9,093
  • 11
  • 18