When to use each method of launching a subprocess in Ruby
1. ``
The Backtick
- defined in Kernel
1. a) %x{}
Percent X < alternate syntax for The Backtick
- defined in parse.y, see discussion
2. system()
- Kernel#system
3. fork()
- Kernel#fork, Process#fork
4. open()
- open a pipe
- Kernel#open
4.a. IO.popen()
< behaves the same as open()
- open a pipe
- IO#popen
4.b. open("|-")
- fork to a pipe
4.c. IO.popen("-")
< behaves the same as open("|-")
- fork to a pipe
- see discussion
5. Open3.popen3()
require 'open3'
- stdlib Open3
6. PTY.spawn()
require 'pty'
- stdlib PTY
7. Shell.transact()
require 'shell'
- stdlib Shell
When should one forsake the trusty back-tick for one of the more complex methods?
Edit 1. Big thanks to Avdi Grimm for his posts describing example usage of each method: #1 (& gist); #2 (& gist); #3.
They are fantastic resources to answer How, but are not explicitly composed to answer when each should be used or Why, and as such IMHO are not complete answers to this question.
Solution 1:
use backticks when you want to easily capture the output of a program in a variable. you probably only want to use this for short-running programs, because this will block.
-
system
is convenient in two different cases:a. You have a long running program and you want the output to print as it runs (e.g.
system("tar zxvf some_big_tarball.tar.gz")
)b.
system
can bypass the shell expansion likeexec
(compare the output ofsystem "echo *"
andsystem "echo", "*"
)system blocks until the subprocess has exited.
-
fork
has a couple different use cases as well:a. You want to run some ruby code in a separate process (e.g.
fork { .... }
b. You want to run a child process (or different program) without blocking progress of your script
fork { exec "bash" }
.fork
is your friend if you want to daemonize your program. IO.popen
is useful when you need to interact with the standard out and standard in of a program. Note that it doesn't capture standard err, so you need to redirect that with2>&1
if you care about that.popen3
gives you a separate file descriptor for standard error (for when you need to capture that separately from standard out)PTY.spawn
is necessary when you want the spawned program to behave like you are running from the terminal. See the difference ofgrep --color=auto pat file
when spawned withsystem
vsPTY.spawn
Solution 2:
Here's a flowchart based on this answer. See also, using script
to emulate a terminal.