類別 PTY
建立並管理偽終端機 (PTY)。另請參閱 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
授權¶ ↑
© Copyright 1998 by Akinori Ito。
此軟體可為此目的自由重新散布,全部或部分,前提是此軟體和應用程式及其衍生品的任何副本都包含此完整的著作權聲明。
此軟體以「原樣」提供,不提供任何明示或暗示的擔保,包括但不限於適銷性、適售性或使用此軟體取得的結果的擔保。
公開類別方法
檢查 pid
指定的子處理程序狀態。如果處理程序仍然執行,則傳回 nil
。
如果處理程序未執行,且 raise
為 true,則會引發 PTY::ChildExited
例外。否則,它會傳回 Process::Status
實例。
pid
-
要檢查的處理程序的處理程序 ID
raise
-
如果
true
且pid
指定的處理程序已停止執行,則會引發PTY::ChildExited
。
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); }
配置一個 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_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 上執行指定的指令。您也可以使用別名 ::getpty
。
指令的控制 tty 設定為 pty 的從屬端裝置,且其標準輸入/輸出/錯誤會重新導向到從屬端裝置。
env
是個選用的雜湊,會提供額外的環境變數給已執行的 pty。
# sets FOO to "bar" PTY.spawn({"FOO"=>"bar"}, "printenv", "FOO") { |r,w,pid| p r.read } #=> "bar\r\n" # unsets FOO PTY.spawn({"FOO"=>nil}, "printenv", "FOO") { |r,w,pid| p r.read } #=> ""
command
和 command_line
是要執行的完整指令,給定一個 String
。任何額外的 arguments
都會傳遞給指令。
傳回值¶ ↑
在非區塊形式中,這會傳回一個大小為 3 的陣列,[r, w, pid]
。
在區塊形式中,這些相同的值會產生到區塊
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; }