类 PTY
创建和管理伪终端(PTYs)。另请参见 en.wikipedia.org/wiki/Pseudo_terminal
PTY 允许您使用 ::open 分配新的终端,或使用 ::spawn 使用特定命令生成新的终端。
示例¶ ↑
在此示例中,我们将更改 factor 命令中的缓冲类型,假设 factor 使用 stdio 进行 stdout 缓冲。
如果使用 IO.pipe 而不是 PTY.open,则此代码将死锁,因为 factor 的 stdout 是完全缓冲的。
# start by requiring the standard library PTY require 'pty' master, slave = PTY.open read, write = IO.pipe pid = spawn("factor", :in=>read, :out=>slave) read.close # we dont need the read slave.close # or the slave # pipe "42" to the factor command write.puts "42" # output the response from factor p master.gets #=> "42: 2 3 7\n" # pipe "144" to factor and print out the response write.puts "144" p master.gets #=> "144: 2 2 2 2 3 3\n" write.close # close the pipe # The result of read operation when pty slave is closed is platform # dependent. ret = begin master.gets # FreeBSD returns nil. rescue Errno::EIO # GNU/Linux raises EIO. nil end p ret #=> nil
许可证¶ ↑
© 版权所有 1998 Akinori Ito。
本软件可以为此目的全部或部分免费重新分发,前提是本软件的任何副本以及本软件及其衍生应用程序中均包含完整的版权声明。
本软件按“原样”提供,不作任何形式的保证,无论是明示的还是暗示的,包括但不限于对适用性,适销性或使用本软件获得的结果的保证。
公共类方法
源代码
static VALUE
pty_check(int argc, VALUE *argv, VALUE self)
{
VALUE pid, exc;
rb_pid_t cpid;
int status;
const int flag =
#ifdef WNOHANG
WNOHANG|
#endif
#ifdef WUNTRACED
WUNTRACED|
#endif
0;
rb_scan_args(argc, argv, "11", &pid, &exc);
cpid = rb_waitpid(NUM2PIDT(pid), &status, flag);
if (cpid == -1 || cpid == 0) return Qnil;
if (!RTEST(exc)) return rb_last_status_get();
raise_from_check(cpid, status);
UNREACHABLE_RETURN(Qnil);
}
检查由 pid 指定的子进程的状态。如果进程仍然存活,则返回 nil。
如果进程未存活,并且 raise 为 true,则将引发 PTY::ChildExited 异常。否则,它将返回一个 Process::Status 实例。
pid-
要检查的进程的进程 ID
raise-
如果
true并且由pid标识的进程不再存活,则会引发PTY::ChildExited。
源代码
static VALUE
pty_open(VALUE klass)
{
int master_fd, slave_fd;
char slavename[DEVICELEN];
getDevice(&master_fd, &slave_fd, slavename, 1);
VALUE master_path = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
VALUE master_io = rb_io_open_descriptor(rb_cIO, master_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX, master_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
VALUE slave_path = rb_obj_freeze(rb_str_new_cstr(slavename));
VALUE slave_file = rb_io_open_descriptor(rb_cFile, slave_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY, slave_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
VALUE assoc = rb_assoc_new(master_io, slave_file);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
}
return assoc;
}
分配一个 pty (伪终端)。
在块形式中,生成包含两个元素的数组(master_io, slave_file),并且块的值从 open 返回。
如果 IO 和 File 在块完成之后尚未关闭,则将关闭它们。
PTY.open {|master, slave| p master #=> #<IO:masterpty:/dev/pts/1> p slave #=> #<File:/dev/pts/1> p slave.path #=> "/dev/pts/1" }
在非块形式中,返回一个包含两个元素的数组 [master_io, slave_file]。
master, slave = PTY.open # do something with master for IO, or the slave file
两种形式的参数都是
IO#raw! 可用于禁用换行符转换
require 'io/console' PTY.open {|m, s| s.raw! # ... }
源代码
static VALUE
pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
char SlaveName[DEVICELEN];
establishShell(argc, argv, &info, SlaveName);
VALUE pty_path = rb_obj_freeze(rb_str_new_cstr(SlaveName));
VALUE rport = rb_io_open_descriptor(
rb_cFile, info.fd, FMODE_READABLE, pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
);
int wpty_fd = rb_cloexec_dup(info.fd);
if (wpty_fd == -1) {
rb_sys_fail("dup()");
}
VALUE wport = rb_io_open_descriptor(
rb_cFile, wpty_fd, FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE | FMODE_SYNC,
pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
);
res = rb_ary_new2(3);
rb_ary_store(res, 0, rport);
rb_ary_store(res, 1, wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
if (rb_block_given_p()) {
rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
return Qnil;
}
return res;
}
在新分配的 pty 上生成指定的命令。您还可以使用别名 ::getpty。
该命令的控制 tty 设置为 pty 的从属设备,并且其标准输入/输出/错误被重定向到从属设备。
env 是一个可选的哈希,它为生成的 pty 提供额外的环境变量。
# sets FOO to "bar" PTY.spawn({"FOO"=>"bar"}, "printenv", "FOO") do |r, w, pid| p r.read #=> "bar\r\n" ensure r.close; w.close; Process.wait(pid) end # unsets FOO PTY.spawn({"FOO"=>nil}, "printenv", "FOO") do |r, w, pid| p r.read #=> "" ensure r.close; w.close; Process.wait(pid) end
command 和 command_line 是要运行的完整命令,给定一个 String。任何其他 arguments 都将传递给命令。
返回值¶ ↑
在非块形式中,这将返回大小为三的数组 [r, w, pid]。
在块形式中,这些相同的值将传递给该块
清理¶ ↑
此方法不会像关闭 IO 或等待子进程那样进行清理,除非在块形式中分离了该进程以防止其成为僵尸进程(请参阅 Process.detach)。任何其他清理都由调用者负责。如果要等待 pid,请务必在执行此操作之前关闭 r 和 w;以相反的顺序执行可能会导致某些操作系统上的死锁。