class PTY
Создаёт и управляет псевдотерминалами (PTY). Смотрите также en.wikipedia.org/wiki/Pseudo_terminal
PTY позволяет вам выделять новые терминалы с помощью ::open или запускать новый терминал со специфической командой с помощью ::spawn.
Пример
В этом примере мы изменим тип буферизации в команде factor, предполагая, что фактор использует stdio для буферизации stdout.
Если вместо PTY.open используется IO.pipe, этот код приводит к тупику, потому что 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 года, Акинори Ито.
Этот программный код может быть свободно перераспределён для этой цели, полностью или частично, при условии, что вся эта информация об авторском праве включена во все копии этого программного обеспечения и приложений, а также производных от них.
Этот программный код предоставляется «как есть», без каких-либо гарантий, явных или подразумеваемых, относительно любых вопросов, включая, но не ограничиваясь, гарантией пригодности для конкретной цели или товарным видом, или полученными результатами от использования этого программного обеспечения.
Методы класса
Исходный код
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-
Идентификатор процесса для проверки
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
Аргументы в обеих формах:
master_io-
главный порт pty, как
IO. slave_file-
ведомый порт pty, как
File. Путь к устройству терминала доступен черезslave_file.path
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].
В форме с блоком эти же значения будут переданы в блок:
r-
Чтение
IOсодержащий стандартный вывод и стандартные ошибки команды w-
Запись
IO, являющийся стандартным вводом команды pid-
Идентификатор процесса для команды.
Очистка
Этот метод не выполняет очистку, например закрытие вводов-выводов или ожидания дочернего процесса, за исключением того, что процесс открепляется в форме с блоком, чтобы избежать превращения его в зомби (см. Process.detach). Любая другая очистка является обязанностью вызывающего кода. Если нужно ожидать pid, убедитесь, что вы закрыли как r, так и w, прежде чем делать это; выполнение в обратном порядке может привести к тупику на некоторых операционных системах.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.