7

I'm quite confused reading the doc of Ruby's system method here. I'm not sure what are commands and what are options. What do I do if I want to execute the following?

wget -pk -nd -P /public/google www.google.com

For security reasons, I'd like to use one of the versions that uses no shell (the second and third forms in the URL I gave, rather than the first)

Mika H.
  • 4,119
  • 11
  • 44
  • 60
  • 1
    You could use backticks. – alex Nov 12 '12 at 03:53
  • `file = system(wget -pk -nd -P /public/google www.google.com)`. Check this http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby – ichigolas Nov 12 '12 at 03:57
  • Sorry, edited to clarify what I meant. – Mika H. Nov 12 '12 at 03:59
  • @alex: But backticks are subject to the same shell problems that `system("string")` is. – mu is too short Nov 12 '12 at 04:03
  • 2
    @nicooga: The problem with `system(string)` is that something unpleasant could be in `string`. Consider what would happen if you have `x = 'www.google.com; rm -rf /some/important/directory'` and then you say `system("wget ... #{x}")`; **don't do it**, think about it. – mu is too short Nov 12 '12 at 04:20

1 Answers1

16

Consider the examples:

system("echo *")
system("echo", "*")

The first one passes the string 'echo *' to the shell to be parsed and executed; that's why system('echo *') produces the same output as saying echo * from the shell prompt: you get a list of files in the current directory. The corresponding argument form is:

commandline : command line string which is passed to the standard shell

The second one bypasses the shell entirely. It will look for echo in the PATH and then execute it with the string '*' as its argument. Since the shell expands wildcards (at least on unixy systems), the * will stay as a simple * and you'll see * as the output. The corresponding argument form here is:

cmdname, arg1, ... : command name and one or more arguments (no shell)

The third form:

[cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)

is used when you want to execute cmdname but have it show up with a different name in ps listings and such. You can see this in action by opening two terminals. Open up irb in one of them and say:

system('sleep', '10')

then quickly switch to the other and look at the ps listing. You should see sleep 10 in there. But, if you give this to irb:

system(['sleep', 'pancakes'], '10')

and check the ps listing, you'll see pancakes 10. Similar two-terminal tricks will show you a shell -c sleep 10 if you say system('sleep 10').

If you supply a Hash as the first argument, then that Hash is used as the environment variables for the spawned process. If you supply a Hash as the final argument, then that Hash is used as options; further documentation on the arguments is, as noted in the system documentation, available under Kernel#spawn.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Thanks for your long answer! What I'm still not entirely sure is, what counts as an "argument"? Does `-pk`, `-nd`, `-P`, `/public/google`, `www.google.com` each count as one argument? – Mika H. Nov 12 '12 at 04:27
  • @MikaH.: Yes, each of those are arguments. – mu is too short Nov 12 '12 at 04:48