[ACCEPTED]-How can Perl's system() print the command that it's running?-system

Accepted answer
Score: 19

I don't know of any default way to do this, but 2 you can define a subroutine to do it for 1 you:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);

And then see it in action:

pbook:~/foo rudd$ perl foo.pl ls
ls
file1   file2   foo.pl
Score: 10

As I understand, system() will print the 6 result of the command, but not assign it. Eg.

[daniel@tux /]$ perl -e '$ls = system("ls"); print "Result: $ls\n"'
bin   dev  home  lost+found  misc  net  proc  sbin     srv  System  tools  var
boot  etc  lib   media       mnt   opt  root  selinux  sys  tmp     usr
Result: 0

Backticks 5 will capture the output of the command and 4 not print it:

[daniel@tux /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
Result: bin
boot
dev
etc
home
lib

etc...

Update: If you want to print 3 the name of the command being system() 'd as well, I 2 think Rudd's approach is good. Repeated here 1 for consolidation:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);
Score: 5

Use open instead. Then you can capture the 1 output of the command.

open(LS,"|ls");
print LS;
Score: 5

Here's an updated execute that will print 1 the results and return them:

sub execute {
  my $cmd = shift;
  print "$cmd\n";
  my $ret = `$cmd`;
  print $ret;
  return $ret;
}
Score: 2

Hmm, interesting how different people are 17 answering this different ways. It looks 16 to me like mk and Daniel Fone interpreted it as wanting 15 to see/manipulate the stdout of the command 14 (neither of their solutions capture stderr 13 fwiw). I think Rudd got closer. One twist 12 you could make on Rudd's response is to 11 overwite the built in system() command with 10 your own version so that you wouldn't have 9 to rewrite existing code to use his execute() command.

using 8 his execute() sub from Rudd's post, you 7 could have something like this at the top 6 of your code:

if ($DEBUG) {
   *{"CORE::GLOBAL::system"} = \&{"main::execute"};
}

I think that will work but 5 I have to admit this is voodoo and it's 4 been a while since I wrote this code. Here's 3 the code I wrote years ago to intercept 2 system calls on a local (calling namespace) or 1 global level at module load time:

  # importing into either the calling or global namespace _must_ be
  # done from import().  Doing it elsewhere will not have desired results.
  delete($opts{handle_system});
  if ($do_system) {
    if ($do_system eq 'local') {
      *{"$callpkg\::system"} = \&{"$_package\::system"};
    } else {
      *{"CORE::GLOBAL::system"} = \&{"$_package\::system"};
    }
  }
Score: 2

Another technique to combine with the others 5 mentioned in the answers is to use the tee command. For 4 example:

open(F, "ls | tee /dev/tty |");
while (<F>) {
    print length($_), "\n";
}
close(F);

This will both print out the files 3 in the current directory (as a consequence 2 of tee /dev/tty) and also print out the length of each 1 filename read.

More Related questions