# I'm a process-spawning idiot

**URL:** <https://rubytalk.org/t/im-a-process-spawning-idiot/33300>\
**Category:** ruby-talk\
**Created:** [29 November 2006 07:00 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300 "2006-11-29T07:00:21Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Devin\_Mullins](https://avatars.discourse-cdn.com/v4/letter/d/958977/32.png) [@Devin\_Mullins](https://rubytalk.org/u/Devin_Mullins)\
**Post date:** [29 November 2006 07:00 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/1 "2006-11-29T07:00:21Z")

</div>

I'm looking for a method that, like Kernel#` and IO::popen, allows me to call out to the system and grab its stdout. However, I'd like it to accept multiple args (like Kernel#system), so I don't have to worry about filenames with spaces and backslashes and the like. Alternatively, I'll take a lib that escapes strings for Kernel#`, provided it works on win32, unix, cygwin...

I'm sure I'm just missing the obvious. Help?

Thanks,  
Devin

---

<div class="post-metadata">

**Author:** ![Paul\_Lutus](https://avatars.discourse-cdn.com/v4/letter/p/2bfe46/32.png) [@Paul\_Lutus](https://rubytalk.org/u/Paul_Lutus)\
**Post date:** [29 November 2006 07:50 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/2 "2006-11-29T07:50:05Z")

</div>

Devin Mullins wrote:

> I'm looking for a method that, like Kernel#` and IO::popen, allows me to  
> call out to the system and grab its stdout. However, I'd like it to  
> accept multiple args (like Kernel#system), so I don't have to worry  
> about filenames with spaces and backslashes and the like. Alternatively,  
> I'll take a lib that escapes strings for Kernel#`, provided it works on  
> win32, unix, cygwin...
> 
> I'm sure I'm just missing the obvious. Help?

You want to what? You want to execute an arbitrary system command and  
collect the command's output?

data = `command arg1 arg2 arg3`

Obviously if the provided command line works in a shell, it will work here,  
and vice versa.

> **···**
>
> --  
> Paul Lutus  
> [http://www.arachnoid.com](http://www.arachnoid.com)

---

<div class="post-metadata">

**Author:** ![Eric\_Hodel1](https://avatars.discourse-cdn.com/v4/letter/e/a9adbd/32.png) [@Eric\_Hodel1](https://rubytalk.org/u/Eric_Hodel1)\
**Post date:** [29 November 2006 07:58 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/3 "2006-11-29T07:58:22Z")

</div>

system 'command', 'arg with spaces' will execute correctly (ARGV[0] will be 'arg with spaces')

`command arg with spaces` requires manual intervention (ARGV[0] will be 'arg').

That said, try playing with shell.rb. I don't really know what it does, though.

> **···**
>
> On Nov 28, 2006, at 2350 , Paul Lutus wrote:
> 
> > Devin Mullins wrote:
> > 
> > > I'm looking for a method that, like Kernel#` and IO::popen, allows me to  
> > > call out to the system and grab its stdout. However, I'd like it to  
> > > accept multiple args (like Kernel#system), so I don't have to worry  
> > > about filenames with spaces and backslashes and the like. Alternatively,  
> > > I'll take a lib that escapes strings for Kernel#`, provided it works on  
> > > win32, unix, cygwin...
> > > 
> > > I'm sure I'm just missing the obvious. Help?
> > 
> > You want to what? You want to execute an arbitrary system command and  
> > collect the command's output?
> > 
> > data = `command arg1 arg2 arg3`
> > 
> > Obviously if the provided command line works in a shell, it will work here,  
> > and vice versa.
> 
> --  
> Eric Hodel - drbrain@segment7.net - [http://blog.segment7.net](http://blog.segment7.net)
> 
> I LIT YOUR GEM ON FIRE!

---

<div class="post-metadata">

**Author:** ![Devin\_Mullins](https://avatars.discourse-cdn.com/v4/letter/d/958977/32.png) [@Devin\_Mullins](https://rubytalk.org/u/Devin_Mullins)\
**Post date:** [29 November 2006 13:57 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/4 "2006-11-29T13:57:40Z")

</div>

Eric Hodel wrote:

> That said, try playing with shell.rb. I don't really know what it does, though.

Thanks!

This Ruby program:  
&nbsp;&nbsp;&nbsp;STDOUT.reopen open('log.txt','w')  
&nbsp;&nbsp;&nbsp;exec 'echo', 'Hi!'  
&nbsp;&nbsp;&nbsp;\_\_END\_\_  
outputs "Hi!" to log.txt.

shell.rb (or, more specifically, shell/process-controller.rb), uses this combined with fork (since exec replaces the process) to do its dirty work.

Downloading win32-process now... 😃

Devin

---

<div class="post-metadata">

**Author:** ![Devin\_Mullins](https://avatars.discourse-cdn.com/v4/letter/d/958977/32.png) [@Devin\_Mullins](https://rubytalk.org/u/Devin_Mullins)\
**Post date:** [29 November 2006 14:40 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/5 "2006-11-29T14:40:12Z")

</div>

For reference's sake, I don't need fork. The same trick works with Kernel#system. Some ugly code:  
&nbsp;&nbsp;&nbsp;inp, out = IO.pipe  
&nbsp;&nbsp;&nbsp;# start Thread.critical  
&nbsp;&nbsp;&nbsp;old\_stdout = STDOUT.dup  
&nbsp;&nbsp;&nbsp;STDOUT.reopen out  
&nbsp;&nbsp;&nbsp;system 'echo', 'matz is nice!'  
&nbsp;&nbsp;&nbsp;STDOUT.reopen old\_stdout  
&nbsp;&nbsp;&nbsp;# end Thread.critical  
&nbsp;&nbsp;&nbsp;out.close  
&nbsp;&nbsp;&nbsp;puts "Hey guess what: #{inp.read}"  
\_\_END\_\_

Out of curiosity, is this one of those places where I'd \_have\_ to use Thread.critical (assuming I don't want other threads putsing to my pipe)?

Devin

Devin Mullins wrote:

> **···**
>
> > This Ruby program:  
> > &nbsp;&nbsp;STDOUT.reopen open('log.txt','w')  
> > &nbsp;&nbsp;exec 'echo', 'Hi!'  
> > &nbsp;&nbsp;\_\_END\_\_  
> > outputs "Hi!" to log.txt.
> > 
> > shell.rb (or, more specifically, shell/process-controller.rb), uses this combined with fork (since exec replaces the process) to do its dirty work.
> > 
> > Downloading win32-process now... 😃

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard6](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@Ara.T.Howard6](https://rubytalk.org/u/Ara.T.Howard6)\
**Post date:** [29 November 2006 14:44 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/6 "2006-11-29T14:44:36Z")

</div>

systemu.rb allows capture of stdout, stderr, and exit\_status and specification  
of stdin in an cross platform way.

NAME

&nbsp;&nbsp;&nbsp;systemu.rb

SYNOPSIS

&nbsp;&nbsp;&nbsp;univeral capture of stdout and stderr and handling of child process pid for windows, \*nix, etc.

URIS

&nbsp;&nbsp;&nbsp;[http://rubyforge.org/projects/codeforpeople/](http://rubyforge.org/projects/codeforpeople/)  
&nbsp;&nbsp;&nbsp;[http://codeforpeople.com/lib/ruby/](http://codeforpeople.com/lib/ruby/)

INSTALL

&nbsp;&nbsp;&nbsp;gem install systemu

SAMPLES

&nbsp;&nbsp;&nbsp;\<========\< samples/a.rb \>========\>

&nbsp;&nbsp;&nbsp;~ \> cat samples/a.rb

> **···**
>
> On Wed, 29 Nov 2006, Devin Mullins wrote:
> 
> > Eric Hodel wrote:
> > 
> > > That said, try playing with shell.rb. I don't really know what it does, though.
> > 
> > Thanks!
> > 
> > This Ruby program:  
> > STDOUT.reopen open('log.txt','w')  
> > exec 'echo', 'Hi!'  
> > \_\_END\_\_  
> > outputs "Hi!" to log.txt.
> > 
> > shell.rb (or, more specifically, shell/process-controller.rb), uses this combined with fork (since exec replaces the process) to do its dirty work.
> > 
> > Downloading win32-process now... 😃
> > 
> > Devin
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# systemu can be used on any platform to return status, stdout, and stderr of  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# any command. unlike other methods like open3/popen4 there is zero danger of  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# full pipes or threading issues hanging your process or subprocess.  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status, stdout, stderr = systemu date  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p [status, stdout, stderr]
> 
> &nbsp;&nbsp;&nbsp;~ \> ruby samples/a.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[#\<Process::Status: pid=9960,exited(0)\>, "Fri Nov 03 17:22:23 MST 2006\n", "Fri Nov 03 17:22:23 MST 2006\n"]
> 
> &nbsp;&nbsp;&nbsp;\<========\< samples/b.rb \>========\>
> 
> &nbsp;&nbsp;&nbsp;~ \> cat samples/b.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# quite a few keys can be passed to the command to alter it's behaviour. if  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# either stdout or stderr is supplied those objects should respond\_to? '\<\<'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# and only status will be returned  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stdout, stderr = '', ''  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status = systemu date, 'stdout' =\> stdout, 'stderr' =\> stderr  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p [status, stdout, stderr]
> 
> &nbsp;&nbsp;&nbsp;~ \> ruby samples/b.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[#\<Process::Status: pid=9965,exited(0)\>, "Fri Nov 03 17:22:23 MST 2006\n", "Fri Nov 03 17:22:23 MST 2006\n"]
> 
> &nbsp;&nbsp;&nbsp;\<========\< samples/c.rb \>========\>
> 
> &nbsp;&nbsp;&nbsp;~ \> cat samples/c.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# of course stdin can be supplied too. synonyms for 'stdin' include '0' and  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 0. the other stdio streams have similar shortcuts  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cat = %q( ruby -e" ARGF.each{|line| puts line} " )
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status = systemu cat, 0=\>'the stdin for cat', 1=\>stdout=''  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts stdout
> 
> &nbsp;&nbsp;&nbsp;~ \> ruby samples/c.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the stdin for cat
> 
> &nbsp;&nbsp;&nbsp;\<========\< samples/d.rb \>========\>
> 
> &nbsp;&nbsp;&nbsp;~ \> cat samples/d.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# the cwd can be supplied  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'tmpdir'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pwd = %q( ruby -e" STDERR.puts Dir.pwd " )
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status = systemu pwd, 2=\>(stderr=''), :cwd=\>Dir.tmpdir  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts stderr
> 
> &nbsp;&nbsp;&nbsp;~ \> ruby samples/d.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/tmp
> 
> &nbsp;&nbsp;&nbsp;\<========\< samples/e.rb \>========\>
> 
> &nbsp;&nbsp;&nbsp;~ \> cat samples/e.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# any environment vars specified are merged into the child's environment  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;env = %q( ruby -r yaml -e" puts ENV['answer'] " )
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status = systemu env, 1=\>stdout='', 'env'=\>{ 'answer' =\> 0b101010 }  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts stdout
> 
> &nbsp;&nbsp;&nbsp;~ \> ruby samples/e.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42
> 
> &nbsp;&nbsp;&nbsp;\<========\< samples/f.rb \>========\>
> 
> &nbsp;&nbsp;&nbsp;~ \> cat samples/f.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# if a block is specified then it is passed the child pid and run in a  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# background thread. note that this thread will \_\_not\_\_ be blocked during the  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# execution of the command so it may do useful work such as killing the child  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# if execution time passes a certain threshold  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;looper = %q( ruby -e" loop{ STDERR.puts Time.now.to\_i; sleep 1 } " )
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status, stdout, stderr =  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;systemu looper do |cid|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 3  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Process.kill 9, cid  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p [status, stdout, stderr]
> 
> &nbsp;&nbsp;&nbsp;~ \> ruby samples/f.rb
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[#\<Process::Status: pid=9985,signaled(SIGKILL=9)\>, "", "1162599744\n1162599745\n1162599746\n1162599747\n"]
> 
> -a  
> --  
> if you want others to be happy, practice compassion.  
> if you want to be happy, practice compassion. -- the dalai lama

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard6](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@Ara.T.Howard6](https://rubytalk.org/u/Ara.T.Howard6)\
**Post date:** [29 November 2006 14:52 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/7 "2006-11-29T14:52:40Z")

</div>

this is an insanely bad idea: a cross platform way to hang you system. try  
this:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;big = 42.chr \* 4242  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inp, out = IO.pipe  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old\_stdout = STDOUT.dup  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STDOUT.reopen out  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;system 'echo', big  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STDOUT.reopen old\_stdout

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> ruby a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# hung process

you can't keep writing to a pipe \_\_unless\_\_ someone is guarunteed to be reading  
from the other end!

make it easy on yourself:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'rubygems'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require 'systemu' # gem install systemu

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;systemu ['echo', 'matz is nice!'], :stdout=\>STDOUT

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;systemu ['echo', 'matz is nice!'], :stdout=\>stdout=''  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p stdout

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;systemu 'cat', :stdin=\>['line1', 'line2'], :stdout=\>stdout  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p stdout

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> ruby a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;matz is nice!  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"matz is nice!\n"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"matz is nice!\nline1line2"

kind regards

-a

> **···**
>
> On Wed, 29 Nov 2006, Devin Mullins wrote:
> 
> > For reference's sake, I don't need fork. The same trick works with Kernel#system. Some ugly code:  
> > inp, out = IO.pipe  
> > # start Thread.critical  
> > old\_stdout = STDOUT.dup  
> > STDOUT.reopen out  
> > system 'echo', 'matz is nice!'  
> > STDOUT.reopen old\_stdout  
> > # end Thread.critical  
> > out.close  
> > puts "Hey guess what: #{inp.read}"  
> > \_\_END\_\_
> 
> --  
> if you want others to be happy, practice compassion.  
> if you want to be happy, practice compassion. -- the dalai lama

---

<div class="post-metadata">

**Author:** ![Devin\_Mullins](https://avatars.discourse-cdn.com/v4/letter/d/958977/32.png) [@Devin\_Mullins](https://rubytalk.org/u/Devin_Mullins)\
**Post date:** [30 November 2006 01:49 UTC](https://rubytalk.org/t/im-a-process-spawning-idiot/33300/8 "2006-11-30T01:49:46Z")

</div>

> \<snip\>  
> this is an insanely bad idea: a cross platform way to hang you system.

well, then. no need to be curt about it. 😛

> gem install systemu

aha! i had a stinking suspicion i should just've emailed you, and not all of ruby-talk. thanks for the info, and the cool lib, ara.

devin  
(tmp\_dir? Marshal.dump? Yikes. Glad I didn't have to write that crap. Quick, someone put in an RCR for Kernel#backtick(cmd, \*args) so this craziness can go away.)

> **···**
>
> ara.t.howard@noaa.gov wrote:
> 
> > On Wed, 29 Nov 2006, Devin Mullins wrote:
