7

On Unix, all these three generate the same result

system("top -H -p $pid -n 1");             #ver1
system("top", "H", "p $pid", "n 1");       #ver2
system("top", "-H", "-p $pid", "-n 1");    #ver3
  • What is the difference between ver2 and ver3?

  • Is there any reason I should use ver2 and ver3, and not ver1?

  • They do not even support piping the results, for example, are there any ver2 and ver3 equivalents of the following call?

    system("top -H -p $pid -n 1 | grep myprocess | wc -l");
    
Lazer
  • 90,700
  • 113
  • 281
  • 364
  • 1
    See also http://stackoverflow.com/questions/3854651/how-can-i-store-the-result-of-a-system-command-in-a-perl-variable by the same user – PP. Oct 04 '10 at 11:31
  • closevoter, this is not a duplicate. At least read the questions before marking. @PP: Did you mean to say it was a duplicate? – Lazer Oct 04 '10 at 12:48
  • 1
    No, I mentioned the link because the questions are related. – PP. Oct 04 '10 at 15:20
  • 1
    I explain a lot of this in _Mastering Perl_ in the security chapter. It's all in the docs, though, too. – brian d foy Oct 05 '10 at 17:07
  • @brian, can you please link the relevant part of the docs? Nothing is mentioned [here](http://perldoc.perl.org/functions/system.html). – Lazer Oct 05 '10 at 18:44
  • Well, I condensed it all into _Mastering Perl_. The rest is up to you. – brian d foy Oct 05 '10 at 23:44

4 Answers4

5

Even it looks same it is not same:

$ perl -e 'system("./test.pl -H -p $$ -n 1");system("./test.pl", "H", "p $$", "n 1");system("./test.pl", "-H", "-p $$", "-n 1");'
-H,-p,10497,-n,1
H,p 10497,n 1
-H,-p 10497,-n 1
$ cat ./test.pl 
#!/usr/bin/perl
$\="\n";
$,=",";
print @ARGV;

It is up to top implementation that it works same. Other applications may not work same.

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
3

Quoth perlfunc for system:

Note that argument processing varies depending on the number of arguments. If there is more than one argument in LIST, or if LIST is an array with more than one value, starts the program given by the first element of the list with arguments given by the rest of the list. If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly to execvp , which is more efficient.

So if $pid is just digits, all are equivalent.

To interpolate results of an arbitrary shell command including pipes use qx and friends.

msw
  • 42,753
  • 9
  • 87
  • 112
3

As a practical reason for using LIST, sometimes your command-line arguments contain spaces or other characters that would confuse your shell.

system("mplayer.exe", "--volume", "75",
       q[C:/Program Files/My Music Player/Music Library/The "Music" Song.mp3]);
mob
  • 117,087
  • 18
  • 149
  • 283
1
  • What is the difference between ver2 and ver3?

Just in what arguments you're passing to top. I don't know of a version of top that will take switches without dashes like some versions of ps do, so you should use version 3.

  • Is there any reason I should use ver2 and ver3, and not ver1?

If you pass a single string to system it will run it via your shell. This means it will be shell interpreted. Any stray spaces or shell meta characters (quotes, dollar signs, etc...) in the arguments would be interpreted and possibly mess things up. It's also a potential security hole.

For example, if $pid was something like '10; echo pwnd; echo ' then you'd run top -H -p 10 then echo pwnd then echo -n1.

So for both safety and security, unless you need shell processing (see below) you should pass system a list.

  • Are there any ver2 and ver3 equivalents which allow pipes?

No, piping and redirection is done by the shell. You have to use something other than system. You can do it with open, but it's a pain in the ass. Easiest way is to use IPC::Run.

use IPC::Run;

my $out;
run ["echo", "foo\nbar\nbaz"], "|",
    ["grep", "ba"],            "|",
    ["wc",   "-l"],
    \$out;
print $out;  # 2

But really if you're just grepping and counting a handful of lines, use Perl.

my $out;
run ["echo", "foo\nbar\nbaz"], '>', \$out;

my $count = grep { /ba/ } split /\n/, $out;
print $count;
Schwern
  • 153,029
  • 25
  • 195
  • 336