在Ruby中何时使用每种子进程启动方法

68

1. `` 反引号

1.a. %x{} 百分号X < 反引号的另一种语法

  • 在parse.y中定义,详情请参阅讨论

2. system()

3. fork()

4. open()

4.a. IO.popen() < 和 open() 行为相同

4.b. open("|-")

  • 分叉到一个管道

4.c. IO.popen("-")open("|-")的行为相同

  • 创建一个管道(pipe)的子进程
  • 参考讨论

5. Open3.popen3()

  • require 'open3'
  • 标准库Open3

6. PTY.spawn()

  • require 'pty'
  • 标准库PTY

7. Shell.transact()

  • require 'shell'
  • 标准库Shell

什么时候应该放弃可靠的反引号(back-tick)而使用更复杂的方法?

编辑1:感谢Avdi Grimm的文章,他描述了每种方法的使用示例:#1 (& gist);#2 (& gist);#3。它们是非常好的资源来回答如何使用,但它们并没有明确回答什么时候应该使用每种方法或为什么使用这些方法,因此在我看来不是这个问题的完整回答。


4个回答

61
  1. 当您想要轻松地将程序输出捕获到变量中时,请使用反引号。 由于这会阻塞进程,因此您可能只想对短时间运行的程序使用。

  2. system 在以下两种情况下很方便:

    a. 您有一个长时间运行的程序,并希望在其运行时打印输出(例如,system("tar zxvf some_big_tarball.tar.gz")

    b. system 可以绕过 shell 扩展(如 exec),请比较 system "echo *"system "echo", "*" 的输出。

    系统会等待子进程退出后才继续执行。

  3. fork 也有一些不同的用例:

    a. 您想要在单独的进程中运行一些 ruby 代码(例如,fork { .... }

    b. 您想要运行一个子进程(或不同的程序),而不会阻止脚本的进度 fork { exec "bash" }

    如果您想使程序成为守护进程,则 fork 是您的好朋友。

  4. IO.popen 在您需要与程序的标准输出和标准输入交互时非常有用。 请注意,它不会捕获标准错误,因此如果您关心标准错误,则需要使用 2>&1 进行重定向。

  5. popen3 为标准错误提供了单独的文件描述符(当您需要将其与标准输出分开捕获时)

  6. PTY.spawn 是必需的,当您想使生成的程序表现得像在终端中运行一样时。 请参考使用 systemPTY.spawn 生成的 grep --color=auto pat file 的区别。


50

fork并非普遍可用,因此有时仍然需要使用spawn - akostadinov

0

除了上面的流程图https://dev59.com/T2w05IYBdhLWcg3wfh2g#30463900,如果有人想要将其作为可编辑的markdown流程图(由mermaid提供支持),这里是它:

```mermaid
flowchart TD

A{{"Do I want to return to my ruby script, ever?"}} -- No --> B(["Use exec()"])
A -- Yes --> C{{"Is it OK to block until the process completes?"}}
C -- Yes --> D{{"Do I need the program's output to be returned?"}}
D -- Yes --> E(["Use backticks `` or %x{}"])
D -- No --> F(["Use system()"])
C -- No --> H{{"Do I need to interact with the output?"}}
H -- Yes --> J{{"Do I want STDERR?"}}
H -- No --> I(["Use fork()"])
J -- Yes --> L{{"Do I want STDERR in its own separate stream?"}}
J -- No --> K(["Use IO.popen()"])
L -- Yes --> M(["Use Open3.popen3()"])
L -- No --> N{{"Use PTY.spawn()"}}

O>"Outputs to STDOUT"] -.- F
P>"You can always emulate a terminal with the BSD utility called script"] -.- H
Q>"Separate child process; good for daemonizing"] -.- I
R>"You can still use 2>&1 to combine STDERR with STDOUT"] -.- K
S>"Emulates a terminal unconditionally"] -.- M

classDef decision fill:#f8fb99;
classDef action fill:#ffaead;
classDef note fill:#ddd,opacity:0.9,font-weight:200;

class A,C,D,H,J,L decision;
class B,E,F,I,K,M,N action;
class O,P,Q,R,S note;
```

0
另外,还有Process.spawn。从文档中可以看到:

这个方法类似于Kernel#system,但它不会等待命令执行完毕。

父进程应该使用Process.wait来收集子进程的终止状态,或者使用Process.detach来注册对其状态的不感兴趣;否则,操作系统可能会积累僵尸进程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接