exec using sh -c or directly running the command, depending on thesystem

X

Xavier Noëlle

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) !
 
A

Albert Schlef

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.)
 
X

Xavier Noëlle

2011/3/2 Albert Schlef said:
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".
 
R

Robert Klemme

2011/3/2 Albert Schlef said:
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...ini= t !

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".

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

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
X

Xavier Noëlle

2011/3/2 Robert Klemme said:
What Ruby versions are you using? =A0Note 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)

--=20
Xavier NOELLE
 
B

Brian Candler

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')
 
X

Xavier Noëlle

2011/3/2 Brian Candler said:
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 ?
 
R

Robert Klemme

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 ^^


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

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,152
Members
46,697
Latest member
AugustNabo

Latest Threads

Top