今天想用ruby
写一个命令行的自动化执行脚本,我们知道ruby
常用的用于执行shell的函数有
Kernel#exec
,system
,backtick(`)
,IO#popen
,Open3#popen3
,但是这次
似乎都没用,首先Kernel#exec
,system
,backtick(`)
不能提供输入。但是在使用
IO#popen
,Open3#popen3
,却发现无法获得标准输出。
考虑如下代码片段
|
|
|
|
结果却发现代码执行的时候卡死,没有任何输出。仔细思考一下执行的过程,事实上上面的代码已经构成了
死锁,我们的代码在等待子进程输出管道的内容,但是子进程却在等待输入的内容,造成了死锁。然而,
如果使用IO#close_write
来关闭输入管道以避免死锁的话,有无法在后续的步骤中进行输入操作。
所以说前述的这些方法只适合“一次输入,获取输出,退出”这样的程序,对于高交互性的程序就爱莫能助了。
所幸ruby
提供了一个名为pty
的标准库(文档),
这个库似乎并不常用,不过这个pty
库提供了一个BSD-PTY设备的接口,通过pty
,我们可以模拟一个真实的终端设备。
关于pty
的详细描述,可以参见维基百科,
回到我们的代码,我们使用pty
改写如下
|
|
在上述代码中标准错误输出和标准输出被合并在了一起。 值得注意的是,由于子进程是独立并且异步执行的,所以我们需要在读取输出管道的时候做一些判断, 以确定输出是否结束,不然还是会造成死锁。