# I'm a process-spawning idiot

**URL:** <https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625>\
**Category:** Ruby\
**Created:** [November 29, 2006, 8:02am UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625 "2006-11-29T08:02:19Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 8:02am UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/1 "2006-11-29T08:02:19Z")

</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:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 8:50am UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/2 "2006-11-29T08:50:26Z")

</div>

Devin M. 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.

---

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 2:59pm UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/3 "2006-11-29T14:59:15Z")

</div>

Eric H. 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

---

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 9:00am UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/4 "2006-11-29T09:00:27Z")

</div>

On Nov 28, 2006, at 2350 , Paul L. wrote:

> > win32, unix, cygwin…  
> > and vice versa.  
> > 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.

–  
Eric H. - removed\_email\_address@domain.invalid - [http://blog.segment7.net](http://blog.segment7.net)

I LIT YOUR GEM ON FIRE!

---

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 3:41pm UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/5 "2006-11-29T15:41:24Z")

</div>

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

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

---

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 3:45pm UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/6 "2006-11-29T15:45:24Z")

</div>

On Wed, 29 Nov 2006, Devin M. wrote:

> 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

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

NAME

systemu.rb

SYNOPSIS

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

URIS

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

INSTALL

gem install systemu

SAMPLES

\<========\< samples/a.rb \>========\>

~ \> cat samples/a.rb

```
 #
 # systemu can be used on any platform to return status, stdout, and 

```

stderr of  
# any command. unlike other methods like open3/popen4 there is  
zero danger of  
# full pipes or threading issues hanging your process or  
subprocess.  
#  
require ‘systemu’

```
   date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t 

```

" )

```
   status, stdout, stderr = systemu date
   p [status, stdout, stderr]

```

~ \> ruby samples/a.rb

```
 [#<Process::Status: pid=9960,exited(0)>, "Fri Nov 03 17:22:23 MST 

```

2006\n", “Fri Nov 03 17:22:23 MST 2006\n”]

\<========\< samples/b.rb \>========\>

~ \> cat samples/b.rb

```
 #
 # quite a few keys can be passed to the command to alter it's 

```

behaviour. if  
# either stdout or stderr is supplied those objects should  
respond\_to? ‘\<\<’  
# and only status will be returned  
#  
require ‘systemu’

```
   date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t 

```

" )

```
   stdout, stderr = '', ''
   status = systemu date, 'stdout' => stdout, 'stderr' => stderr
   p [status, stdout, stderr]

```

~ \> ruby samples/b.rb

```
 [#<Process::Status: pid=9965,exited(0)>, "Fri Nov 03 17:22:23 MST 

```

2006\n", “Fri Nov 03 17:22:23 MST 2006\n”]

\<========\< samples/c.rb \>========\>

~ \> cat samples/c.rb

```
 #
 # of course stdin can be supplied too. synonyms for 'stdin' 

```

include ‘0’ and  
# 0. the other stdio streams have similar shortcuts  
#  
require ‘systemu’

```
   cat = %q( ruby -e" ARGF.each{|line| puts line} " )

   status = systemu cat, 0=>'the stdin for cat', 1=>stdout=''
   puts stdout

```

~ \> ruby samples/c.rb

```
 the stdin for cat

```

\<========\< samples/d.rb \>========\>

~ \> cat samples/d.rb

```
 #
 # the cwd can be supplied
 #
   require 'systemu'
   require 'tmpdir'

   pwd = %q( ruby -e" STDERR.puts Dir.pwd " )

   status = systemu pwd, 2=>(stderr=''), :cwd=>Dir.tmpdir
   puts stderr

```

~ \> ruby samples/d.rb

```
 /tmp

```

\<========\< samples/e.rb \>========\>

~ \> cat samples/e.rb

```
 #
 # any environment vars specified are merged into the child's 

```

environment  
#  
require ‘systemu’

```
   env = %q( ruby -r yaml -e" puts ENV['answer'] " )

   status = systemu env, 1=>stdout='', 'env'=>{ 'answer' => 0b101010 

```

}  
puts stdout

~ \> ruby samples/e.rb

```
 42

```

\<========\< samples/f.rb \>========\>

~ \> cat samples/f.rb

```
 #
 # if a block is specified then it is passed the child pid and run 

```

in a  
# background thread. note that this thread will **not** be blocked  
during the  
# execution of the command so it may do useful work such as killing  
the child  
# if execution time passes a certain threshold  
#  
require ‘systemu’

```
   looper = %q( ruby -e" loop{ STDERR.puts Time.now.to_i; sleep 1 } 

```

" )

```
   status, stdout, stderr =
     systemu looper do |cid|
       sleep 3
       Process.kill 9, cid
     end

   p [status, stdout, stderr]

```

~ \> ruby samples/f.rb

```
 [#<Process::Status: pid=9985,signaled(SIGKILL=9)>, "", 

```

“1162599744\n1162599745\n1162599746\n1162599747\n”]

-a

---

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 29, 2006, 3:53pm UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/7 "2006-11-29T15:53:28Z")

</div>

On Wed, 29 Nov 2006, Devin M. wrote:

> puts “Hey guess what: #{inp.read}”  
> **END**

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

```
 harp:~ > cat a.rb
 big = 42.chr * 4242
 inp, out = IO.pipe
 old_stdout = STDOUT.dup
 STDOUT.reopen out
 system 'echo', big
 STDOUT.reopen old_stdout

 harp:~ > ruby a.rb
 # 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:

```
 harp:~ > cat a.rb
 require 'rubygems'
 require 'systemu' # gem install systemu

 systemu ['echo', 'matz is nice!'], :stdout=>STDOUT

 systemu ['echo', 'matz is nice!'], :stdout=>stdout=''
 p stdout

 systemu 'cat', :stdin=>['line1', 'line2'], :stdout=>stdout
 p stdout

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

```

kind regards

-a

---

<div class="post-metadata">

**Author:** ![twifkak](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a88e4f/32.png) [@twifkak](https://www.ruby-forum.com/u/twifkak)\
**Post date:** [November 30, 2006, 2:50am UTC](https://www.ruby-forum.com/t/im-a-process-spawning-idiot/77625/8 "2006-11-30T02:50:12Z")

</div>

removed\_email\_address@domain.invalid wrote:

> On Wed, 29 Nov 2006, Devin M. wrote:  
>   
> 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.)
