Wrote Joe Van Dyk <joevandyk@gmail.com>, on Thu, Mar 31, 2005 at 07:58:11AM +0900:
Say I want to start a long running shell process (and monitor that process).
def start_process @process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
end
end
However, @process_id doesn't contain the pid of the cat process. How
can I capture the pid of that process?
You can't, not like this anyhow. You aren't running cat directly, you
are calling the shell, /bin/sh, which is processing the redirect command
(>/dev/null). Only the shell knows the pid of cat. You actually have
So there are 3 processes inherited from your main ruby executable.
Kernel.fork/exec/system are fairly thin wrappers around the C
equivalents, so a unix prog manual should cover whats happening, as well
as ways of doing whatever you are trying to do.
To ensure that the called program really runs as the child of the main
process (and not a further descendent), you have to code it in a
relatively low-level way; in the above case it would look like
def start_process @process_id = fork do
File.reopen $stdin, File.open("/dev/null","w")
exec %w(cat /dev/zero)
end
end
(In this case, 'exec "cat /dev/zero"' would do as well. Ruby's exec is a
bastardized one, not just an interface to the posix exec* calls: it
tries to find out by itself whether to exec the program directly or to
do it via shell. In general, passing an array to exec protects from
shell expansion.)
I'm working on a lib which makes it easier, eg. you could do with it:
def start_process
po = Pope.new
po.do(%w(cat /dev/zero), 1 => "/dev/null").end @process_id = po.actors[0].child
end
Csaba
···
On 2005-03-30, Joe Van Dyk <joevandyk@gmail.com> wrote:
Say I want to start a long running shell process (and monitor that process).
def start_process @process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
end
end
However, @process_id doesn't contain the pid of the cat process. How
can I capture the pid of that process?
It won't, because Kernel.system also does a fork, runs the 'cat' as a child,
waits for it to finish, and then continues.
You will get the pid of the cat process if you change Kernel.system "cat..."
to
exec "cat ..."
But then, the child Ruby process *becomes* cat at that point, and so when
cat terminates, the child terminates.
If you want to capture the pid of the 'cat' then you can reimplement
Kernel.system yourself - which is basically just fork and exec anyway.
It depends what you want to do with the variable @process_id later. If you
just want the child to run cat and then terminate, then 'exec' is what you
want.
In fact, I can't see what else you would want. Suppose I wrote:
def start_process @process_id = fork do
Kernel.system "cat /dev/zero > /dev/null"
Kernel.system "cat /dev/null > /dev/null"
Kernel.system "cat /dev/zero > /dev/null"
end
end
which process ID would you want returned in @process_id ? You currently get
the (child) Ruby process, which then runs three grandchildren one after
another. I can't see how else it would usefully work, unless you get the pid
of each of the three grandchildren and communicate it back to the parent
somehow (e.g. over a socket). The pid for each grandchild won't be known
until that particular grandchild is started, of course.
Regards,
Brian.
···
On Thu, Mar 31, 2005 at 09:02:02AM +0900, Joe Van Dyk wrote:
On Wed, 30 Mar 2005 14:57:51 -0800, Joe Van Dyk <joevandyk@gmail.com> wrote:
> Say I want to start a long running shell process (and monitor that process).
>
> def start_process
> @process_id = fork do
> Kernel.system "cat /dev/zero > /dev/null"
> end
> end
>
> However, @process_id doesn't contain the pid of the cat process. How
> can I capture the pid of that process?