Ruby's Kernel::exec (and system and %x)

On Jan 8, 2008, at 9:49 AM, JJ wrote:

The right answer (because it does not use the shell):

exec(“tolower”, str)

So do you have a solution for executing a file with no args? Or is:
exec([cmd, cmd]) the preferred one?

BTW, I meant
exec([cmd, “”]) instead of exec(cmd, “”)

On Jan 8, 2008, at 3:19 PM, JJ wrote:

The first could be Kernel::exec, and would simply run the process
given. No shell interpretation would ever be done on the argument(s).
Give it one string, and that’s the program it runs. Give it multiple
strings to pass multiple arguments.

Yes, but in the Unix/C world exec() replaces the existing program and
so exec() without fork() is a not-so-useful combination. For
whatever reason it came to pass that Kernel#exec on windows is
actually a Windows version of fork/exec making exec
non-portable.

A second routine, “Kernel::exec_cmd” let’s call it, could take in
exactly one string, and would pass it through the platform’s command
interpreter. This would be documented with all the ugly warnings that
are required so people don’t write

You are describing “Kernel::system” without the funny two-element
array caveat.

I think a better partitioning of the problem would be:

fork/exec: craft what you need, only available on *nix systems
system: execute a command line via the command-interpreter
run: execute a program without using the command-interpreter

I just made up the name ‘run’. I don’t think there are standards
that specify such an interface, which is why exec/system have been
munged, I guess.

Gary W.

On Jan 8, 2008, at 9:59 AM, JJ wrote:

exec( { $cmd } $cmd );
Thank you. This executes the command directly and doesn’t use a sub-
shell. This is exactly what I was looking for.

How would one pass args here, though?
exec( ["/usr/bin/ls", “ls”], “-al”)

Is that right?

On Jan 8, 2008, at 3:19 PM, JJ wrote:

I believe:

system(cmd, “http://www.google.com”)

would also skip the shell entirely, since you are providing more than
one argument to system.

Correct. It is only the one argument form that uses the shell.

Then I retract my previous statement! Thank you!

How would one pass args here, though?
exec( ["/usr/bin/ls", “ls”], “-al”)

Is that right?

Yes, that is right. You can also use the simple form

exec( “/usr/bin/ls”, “-al” )

(or wherever your ls lives). Two or more arguments to “exec” forces
non-shell mode.

-JJ

On Jan 8, 4:41 pm, thefed [email protected] wrote:

But wouldn’t that affect the program cmd, because it is having
something passed to it?

No. This code

exec([cmd, cmd])

is running cmd with no arguments. The second occurrence of “cmd” is
what is actually passed in to the process as its program name
(available to C programs via argv[0] in main(), for example).

So with the two-item list, there is no shell interpretation. To add
arguments, use

exec([cmd, cmd], arg, arg)

but that is the same as

exec(cmd, arg, arg)

simply because once you have at least two arguments to “exec”, it
behaves in the no-shell fashion anyhow.

One could “trick” a program by running

exec([cmd, “string”], arg, arg)

and the program would execute, but see “string” as how it was invoked.
This confuses some applications, but is possible.

-JJ

system() always go to a shell.

No, not true. system() always lets the Ruby process continue on after
the sub-program is finished, but a system() with two or more arguments
doesn’t run any shell. It runs the sub-program directly as a child.

The same rules apply to exec() and system() that have been discussed
in this thread.

-JJ

On Jan 8, 2008, at 11:22 AM, Gary W. wrote:

I just wanted to point out that if you are passing arguments to the
program you can use:

system(cmd, arg1, arg2)

system() always go to a shell.

not-so-useful combination.
Well, I argue that exec() without fork() is useful in any world, but
it may not be available in some. It can be poorly emulated by
CreateProcess() and exit().

My point was not this though; it was simply that instead of having one
routine behave in two very different ways (exec via shell and exec
directly), there should have been two routines. Getting those confused
is the source of many, many bugs.

I would bet that any piece of code you gave me in Perl or Ruby (or any
other language that supports this idiom) that used system() or exec()
would have a very high chance of containing bugs related to this very
problem. I’ve seen it all the time.

I think a better partitioning of the problem would be:

fork/exec: craft what you need, only available on
*nix systems
system: execute a command line via the
command-interpreter
run: execute a program without using the
command-interpreter

Well, my exec and exec_cmd suggestions were meant to have analogs of
system and system_cmd that did the implicit fork on unix. My exec is
like your first exec, except there are two - one via the shell and one
via the system call.

My system is like your system, and my system_cmd is like your run.
We’re speaking the same language; just using different words.

-JJ