# Calling a subprocess with specific arguments and capturing its output?

**URL:** <https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761>\
**Category:** Ruby\
**Created:** [November 11, 2009, 12:01am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761 "2009-11-11T00:01:33Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 12:01am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/1 "2009-11-11T00:01:33Z")

</div>

Hi. I haven’t written Ruby in a while, and I was wondering if someone  
could help with a problem I’ve never managed to solve. I’m writing a  
shell script that takes filenames as its arguments, and calls “du” to  
get their size. Because I don’t want to have to escape everything  
perfectly, I was looking for a function with a syntax that allows  
separate arguments, like system(“du”, “-sh”, filename).

system() doesn’t allow me to capture the output of the subprocess,  
while popen , ``, and %x() don’t let me specify a list of discrete  
arguments. Is there an elegant solution to this problem? My current  
solution is to just escape the arguments and put them into a string,  
but this is ugly and buggy.

Thanks in advance!  
-Dan

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 12:25am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/2 "2009-11-11T00:25:33Z")

</div>

On Nov 10, 6:00 pm, Dan Q [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hi. I haven’t written Ruby in a while, and I was wondering if someone  
> could help with a problem I’ve never managed to solve. I’m writing a  
> shell script that takes filenames as its arguments, and calls “du” to  
> get their size. Because I don’t want to have to escape everything  
> perfectly, I was looking for a function with a syntax that allows  
> separate arguments, like system(“du”, “-sh”, filename).

def backtick(cmd,\*args)  
IO.popen(‘-’) {|f| f ? f.read : exec(cmd,\*args)}  
end

backtick ‘du’, ‘-sh’, filename

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 12:43am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/3 "2009-11-11T00:43:41Z")

</div>

From: “Dan Q” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> arguments. Is there an elegant solution to this problem? My current  
> solution is to just escape the arguments and put them into a string,  
> but this is ugly and buggy.

One possibility might be to let Shellwords handle the  
escaping:

irb(main):001:0\> require ‘shellwords’  
irb(main):002:0\> args = [“foo”, “bar baz”, “mary ‘had’ a”, ‘little  
“lamb” and stuff’]  
irb(main):003:0\> puts( args.map {|a| a.shellescape}.join(" ") )  
foo bar\ baz mary\ 'had'\ a little\ "lamb"\ and\ stuff

Alternately, if you can use ruby 1.9.x, there appears to be  
a very powerful new Kernel.spawn command. (See the `ri`  
documentation, several pages…)

Also in 1.9.x, it appears to now be possible to pass an  
Array for the command arguments to popen:

irb(main):001:0\> IO.popen([“ls”, “-l”, “GL\_GameOfLife.zip”,  
“quake3-1.32b-source.zip”], “r”) {|io| puts(io.read)}  
-rw------- 1 billk billk 3540592 Feb 23 2009 GL\_GameOfLife.zip  
-rw------- 1 billk billk 5724791 Sep 21 2005 quake3-1.32b-source.zip

Hope this helps,

Bill

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 12:47am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/4 "2009-11-11T00:47:12Z")

</div>

> def backtick(cmd,\*args)  
> IO.popen(’-’) {|f| f ? f.read : exec(cmd,\*args)}  
> end
> 
> backtick ‘du’, ‘-sh’, filename

Thanks! That’s a very nice solution, and more concise than I would  
have thought possible. I’ll use this until ruby-1.9 or 2.0 becomes  
standard.

-Dan

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 12:49am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/5 "2009-11-11T00:49:32Z")

</div>

On Tue, Nov 10, 2009 at 5:43 PM, Bill K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Alternately, if you can use ruby 1.9.x, there appears to be  
> a very powerful new Kernel.spawn command. (See the `ri`  
> documentation, several pages…)
> 
> Also in 1.9.x, it appears to now be possible to pass an Array for the  
> command arguments to popen:
> 
> irb(main):001:0\> IO.popen([“ls”, “-l”, “GL\_GameOfLife.zip”,  
> “quake3-1.32b-source.zip”], “r”) {|io| puts(io.read)}

Thanks, Bill. I’m glad to hear that the standard library will be  
getting the capability to do this without a hack, because it seems  
like a big omission in ruby-1.8.

-Dan

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 9:46am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/6 "2009-11-11T09:46:14Z")

</div>

On Tue, Nov 10, 2009 at 9:48 PM, Tony A. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> On Tue, Nov 10, 2009 at 4:00 PM, Dan Q [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > I was looking for a function with a syntax that allows  
> > separate arguments, like system(“du”, “-sh”, filename)
> 
> Why is this any harder than?
> 
> `#{cmd} #{args.map { |arg| arg.to_s.inspect }.join(' ')}`

That comes a lot closer to working than I had expected 😉  
I’d rather not deal with escaping, at all. Won’t shell commands in  
backticks be run differently, depending on what the system shell is?  
I’m not sure whether all unix shells have similar escaping syntax.

The escaping done by inspect() seems to fail when the filename begins  
with whitespace or contains a newline.

-Dan

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 4:48am UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/7 "2009-11-11T04:48:57Z")

</div>

On Tue, Nov 10, 2009 at 4:00 PM, Dan Q [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I was looking for a function with a syntax that allows  
> separate arguments, like system(“du”, “-sh”, filename)

Why is this any harder than?

`#{cmd} #{args.map { |arg| arg.to_s.inspect }.join(' ')}`

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 3:41pm UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/8 "2009-11-11T15:41:33Z")

</div>

2009/11/11 Dan Q [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> That comes a lot closer to working than I had expected 😉  
> I’d rather not deal with escaping, at all. Won’t shell commands in  
> backticks be run differently, depending on what the system shell is?  
> I’m not sure whether all unix shells have similar escaping syntax.
> 
> The escaping done by inspect() seems to fail when the filename begins  
> with whitespace or contains a newline.

If you are on 1.9, escaping is superfluous: you can pass an Array of  
arguments directly:

irb(main):001:0\> IO.popen(%w{echo \*}, “r”) {|io| puts io.read}  
\*  
=\> nil  
irb(main):002:0\> IO.popen([“ls”, “-a”, “-F”], “r”) {|io| puts io.read}  
./  
…/  
=\> nil

This is a lot safer, significantly less error prone and is probably  
more efficient as well (because there is no shell needed for parsing  
the command line).

As far as I can see this does not work in 1.8.7.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![Dan\_Q](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/eb9ed0/32.png) [@Dan\_Q](https://www.ruby-forum.com/u/Dan_Q)\
**Post date:** [November 11, 2009, 4:02pm UTC](https://www.ruby-forum.com/t/calling-a-subprocess-with-specific-arguments-and-capturing-its-output/178761/9 "2009-11-11T16:02:02Z")

</div>

On Nov 11, 2009, at 2:45 AM, Dan Q wrote:

> Won’t shell commands in backticks be run differently, depending on what the system shell is? I’m not sure whether all unix shells have similar escaping syntax.

I don’t believe so. I think backticks will default to the lowest common  
denominator of sh.

James Edward G. II
