Exec using sh -c or directly running the command, depending on the system

Hello !
I’m stuck in a situation I don’t understand and I’m looking for clues
to know what and where to search explanations.
The problem is, as stated in the title, that my subprocess is
sometimes runned using “sh -c ruby runned.rb” and sometimes directly
“ruby runned.rb” (as seen in top), depending on the system: sh -c with
Ubuntu 10.4, directly with Debian 5 and Gentoo.

The scripts are as follow:
--------------------------->8--------------------------------------

runned.rb

puts Process.pid
puts Process.ppid

runner.rb

def runProcess(cmd)
pid = nil

begin
pid = fork do
exec(cmd)
exit 1
end
rescue Errno::ENOENT
$stderr.puts e
end
return pid
end

runProcess(‘ruby “runned.rb”’, true)
--------------------------->8--------------------------------------

Thanks in advance and don’t hesitate to give me a Google search to
solve my problem (I tried many of them, but none worked) !

Ruby tells the shell to execute the command (that’s why you see “sh -c”)
because only the shell knows to parse the command string (special
characters, redirections, etc.). The shell, in its turn, executes the
program(s) mentioned in the command string.

In other words: your ‘top’ (I use ‘htop’, which is better) should show
two processes: “sh -c …” and “ruby …”. The latter is a child of
the former. If you’re using ‘htop’ you can hit ‘t’ to see the list
formatted as a tree: you’ll see that the latter is indeed a child of the
former. Perhaps your Debian’s ‘top’ is configured a bit differently than
your Ubuntu’s and that’s why you don’t see the exact same picture. I’m
using Ubuntu and I see both processes.

(BTW, you can replace ‘ruby “runned.rb”’ with ‘exec ruby “runned.rb”’ to
tell the shell to throw away its own proceess. But don’t do this,
because it’s not portable.)

2011/3/2 Albert S. [email protected]:

Ruby tells the shell to execute the command (that’s why you see “sh -c”)
[…]

Thanks for your explanations, but this is along the lines of what I
already understood.
I mentionned top to explain the problem more directly but I know that
the problem is not due do top; in fact, I already use htop on both
machines and the tree view showed me what I stated in my original
post.

To be more precise, the output of my script, on my Debian and Gentoo
machines, looks like this:
6750
1

These numbers are respectively the PID and parent PID of my
process…init !

But on my Ubuntu machine, it’s something like:
16055
16050

The first is the Ruby script’s PID and the second is the PID of “sh -c”.

2011/3/2 Robert K. [email protected]:

What Ruby versions are you using? Note that there are some changes
between 1.8 and 1.9 in this area, namely that system, IO.popen etc.
accept a list of strings which prevents passing the command to a
shell.

$ ruby --version
ruby 1.9.0 (2008-10-04 revision 19669) [x86_64-linux] (Ubuntu)
ruby 1.9.0 (2008-06-20 revision 17482) [x86_64-linux] (Debian)
ruby 1.9.1p243 (2009-07-16 revision 24175) [x86_64-linux] (Gentoo)

On Wed, Mar 2, 2011 at 12:06 PM, Xavier N. [email protected]
wrote:

The first is the Ruby script’s PID and the second is the PID of “sh -c”.

What Ruby versions are you using? Note that there are some changes
between 1.8 and 1.9 in this area, namely that system, IO.popen etc.
accept a list of strings which prevents passing the command to a
shell.

Although I may also be that the shell behaves differently on both
systems.

Kind regards

robert

Looks like there was a change in Ruby, where perhaps it now does an
optimisation to check for cases where a shell isn’t required (e.g. no
pipelines or redirection)

You could make it consistent by using the multi-argument form of exec,
which I believe will bypass the shell in all cases:

--------------------------->8--------------------------------------

runned.rb

puts Process.pid
puts Process.ppid

runner.rb

def runProcess(cmd)

def runProcess(*cmd)

pid = nil

begin
pid = fork do
exec(cmd)

exec(*cmd)

  exit 1
end

rescue Errno::ENOENT
$stderr.puts e
end
return pid
end

runProcess(‘ruby “runned.rb”’, true)

runProcess(’/usr/bin/ruby’, ‘runned.rb’)

2011/3/2 Brian C. [email protected]:

Looks like there was a change in Ruby, where perhaps it now does an
optimisation to check for cases where a shell isn’t required (e.g. no
pipelines or redirection)

That’s what I noticed with quoting, but I never managed to take
advantage of this feature.
Well, more precisely, I tried to cheat Ruby by quoting every command
line argument, which works on a system, but not the others (don’t know
if it’s a matter of version, system, or something else). What works is
to append a fake redirection to the command itself, but it’s…ugly ^^

You could make it consistent by using the multi-argument form of exec,
which I believe will bypass the shell in all cases:

Works in this case, thanks !

What about the case in which a shell is needed ? Is there a way to
force Ruby to use a subshell instead of doing everything by itself ?

On Wed, Mar 2, 2011 at 2:29 PM, Xavier N. [email protected]
wrote:

to append a fake redirection to the command itself, but it’s…ugly ^^

You could make it consistent by using the multi-argument form of exec,
which I believe will bypass the shell in all cases:

Works in this case, thanks !

What about the case in which a shell is needed ? Is there a way to
force Ruby to use a subshell instead of doing everything by itself ?

You can always explicitly invoke the shell.

ruby19 -e 'exec(ENV[“SHELL”], “-c”, “whatever you like”)

Cheers

robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs