我有一个Ruby脚本,它生成一个进程并使用expect等待输入请求,提供该输入,然后在进程完成时,生成一个新进程.
最初的问题是脚本没有等待第一个进程完成,并执行脚本中的下一行.
所以我添加Process.wait(PID)的剧本,但现在的脚本挂起等待输入第二PTY.spawn
的Process.wait(pid)
.
我正在使用Ruby 1.9.2运行脚本,因为我知道Ruby 1.8.7中存在一些问题PTY.spawn
.
该脚本如下所示:
#!/usr/bin/env ruby
require 'pty'
require 'expect'
PTY.spawn(" apt-get install policycoreutils ") do |reader, writer, pid|
puts reader.expect(/Do you want to continue/)
writer.printf("Y\n")
Process.wait(pid)
end
PTY.spawn(" apt-get install libmagick9-dev ") do |reader, writer, pid|
puts reader.expect(/Do you want to continue/)
writer.printf("Y\n")
Process.wait(pid)
end
Run Code Online (Sandbox Code Playgroud)
有谁知道脚本为什么会挂在Process.wait(pid)
第二个PTY.spawn
?
这是一个让我发疯的问题,我想不出解决办法。我的程序:
#!/usr/bin/sh
ssh -t myuser@anotherhost "cat ~/severalLineFile"
Run Code Online (Sandbox Code Playgroud)
和~/severalLineFile
上anotherhost
看起来像:
line1
line2
line3
line4
line5
line6
Run Code Online (Sandbox Code Playgroud)
当我自己运行我的程序时,终端的输出看起来像预期的那样。但是,当调整我的终端大小使其只有 5 行,并将我的程序通过管道减少时,它看起来像:
line1
line2
line3
line4
:
Run Code Online (Sandbox Code Playgroud)
并且在那时按下空格键时,它会打印出line5
和line6
(以及任何其他行),例如:
line5
line6
Run Code Online (Sandbox Code Playgroud)
现在我明白这是在伪终端中运行 ssh 的结果,并且这种阶梯式的发生是因为换行符中包含回车符。我试过使用,stty ocrnl
但这并没有达到我想要的效果,即在我按下空格键后, less 的初始打印表现得像所有东西。
顺便说一句,我需要ssh
在-t
模式下运行,因为我希望所有ctrl+C
键盘中断都能进入远程进程。如果在这方面有解决方案,我全神贯注。我在 Linux Server 6.1 上,终端是通过 Mac OS 10.6.8
我还尝试\r\n
将伪终端生成的 替换为\n
,但这并不能解决问题。
prog2
不退出CTRL+D
。为什么然后prog1
退出CTRL+D
?更奇怪的是,信号处理程序不执行任何操作,尽管它以某种方式影响最终结果......
下面两个程序的区别仅在于prog1.c
sigaction()
使用了in,以及prog2.c
signal()
使用了in:
@@ -39,10 +39,7 @@
/* read from loopback tty */
if (cpid > 0) {
/* this is the strange part */
- struct sigaction sa;
- sa.sa_handler = child_handler;
- sa.sa_flags = 0;
- sigaction(SIGCHLD, &sa, NULL);
+ signal(SIGCHLD, child_handler);
struct termios tty;
tcgetattr(fd, &tty);
Run Code Online (Sandbox Code Playgroud)
每个程序都只是打开一个环回 tty 并将其自身分成两个进程,其中一个进程从 tty 读取响应,另一个进程将数据写入 tty 设备。然后将从环回tty虚拟设备接收到的数据输出到控制终端。
编译prog1
并prog2
使用-lutil
选项。启动每个程序并输入hello<CTRL+D>
. 这会产生以下输出:
$ ./prog1 …
Run Code Online (Sandbox Code Playgroud) 阅读了包括http://www.linusakesson.net/programming/tty/在内的各种资源后, 我仍然对伪终端的结构和使用感到困惑和好奇在 linux 终端(bash 不是 tty)中,我们有三个流:
每个都有一个文件描述符。这些文件描述符映射到流 FILE*。例如,我们可以使用 fileno() 和 fdopen() 在它们之间进行切换。
我可以用 pty 做什么?
我通常认为 stdout、stdin 和 stderr 与进程相关联。我认为说有一个与 pty 相关联的 stdout、stdin 和 stderr 是不正确的。那么给定一个 pty(对于像 bash 这样的进程而不是它的 pid),你如何获得它们并将它们连接到 bash 意义上的终端?
单个文件描述符(对于 pty)如何映射到三个流?(显然它没有)它可以以某种方式映射到进程吗?
在使用 openpty() 时,我认为要连接主终端和从终端上的进程,您需要为 stdin、stdout 和 stderr 设置单独的管道,并有一个选择循环连接它们并在它们之间传输数据。
但是,您是否可以假设 stdin 和 stdout 已连接(通过 tty)并仅设置一个 stderr 管道以避免合并 stdout 和 stderr?
如果我们有一个 master 和 slave 进程,“额外”的 tty 实际上为我们做什么?
以下是我认为我知道并且相关的一些事情:
所述openpty()函数返回一对表示的伪终端的主设备和从设备的端部的文件描述符。
每个文件描述符指向字符设备 - 见https://man7.org/linux/man-pages/man7/pty.7.html
现在 Unix 中的设备只是特殊文件,因此文件描述符是有意义的。
bash 终端具有三个流,但 tty …