使用命令行在进程启动后捕获标准输入/错误/输出?

9
谢谢!我的用例是:我开始了一个冗长的交互式“配置”过程(例如在“屏幕”下),然后意识到我需要始终回答“否”,直到看到特定的关键字。手动进行此操作似乎浪费时间(更不用说我可能会轻松错过关键字..)
因此,似乎我想要将 STDERR / STDOUT 的副本传输到过滤器中,并且还可以使用命令行在控制台进程启动后将其注入 STDIN?有现成的解决方案吗?
以下工具似乎有所帮助。要捕获输出,请使用:
strace -ewrite -p $PID

虽然代码(显示像:write(#,))不够简洁,但它是可行的!但是它是否正确处理UTF8呢?

若要重定向输出,请执行以下操作:

printf '..input..' >/dev/pts/33

但是如何找到正确的设备并不清楚。

你应该将你的解决方案作为答案添加并接受它。 - Daenyth
3个回答

5

在Linux中解决(显然与Linux有关):

reptyr -s PID 

将一个进程附加到另一个终端,并将其输入和输出公开为管道。


3
这是可能的,但不太美观。步骤如下:
  1. 使用 gdb 附加到已在运行的进程
  2. 运行 p close(<fd>),其中 <fd> 是您想要更改的文件描述符
  3. 运行 p creat("<path to file">, <perms>) 将关闭的 fd 的输出发送到其他地方
请参阅此链接获取更详细的信息。

4
与其在文件描述符上调用 close() 方法,你可以先创建一个新的文件描述符(使用 creat()open() 等方法),然后使用 dup2() 方法替换你想要捕获的文件描述符,最后再关闭新的文件描述符。原因是 open() 等方法总会返回可用的最低文件描述符,因此如果你先关闭了一个文件描述符然后马上打开一个新的,就不能保证你会获得相同的文件描述符。对于标准输入/输出/错误(文件描述符 0、1、2)来说可能不太重要,但对于一般情况值得一提。 - FatalError
这个小程序 reptyr -s PID 就是做这件事的。 - John Quilder

1

你为什么想要这样做?

在可移植的 POSIX 方式下是不可能的!也许打开进程1234的伪文件 /proc/1234/fd/0、/proc/1234/fd/1和/proc/1234/fd/3 可能是一个丑陋的可能性!即使在某些情况下(例如对于管道),这也可能行不通。

特别地,我认为如果没有人读取管道,那么发送给该进程的 SIGPIPE 的语义将会被破坏...

而且我不相信您能保持类似 stdout 的伪终端质量。

因此基本上,您最好找到另一种实现您总体目标的方法,您并没有明确说明这一点。

如果您的用例是一些奇怪的 configure 脚本,您可以重新启动它并使用自己的脚本(在 shell、python、perl 等中)喂入它。不要浪费时间去尝试捕获现有的 configure 进程,只需适当地重新启动它。

同时也要看一下 screen 命令(以及它的实现方式!)


谢谢!我的使用情况是:我开始了一个冗长的交互式“配置”过程(比如在“屏幕”下),然后意识到我需要回答“否”。 - John Quilder
谢谢!我的使用案例是:我开始了一个漫长的交互式“配置”过程(比如在“screen”下),然后意识到我需要总是回答“否”,直到看到特定的关键字。手动处理这个过程很浪费时间(更不用说我可能会轻易错过该关键字)。 - John Quilder
再次感谢!我的观点是,有时候能够做到这一点会非常方便,对于任何进程都是如此;'configure'只是一个例子。'screen'可以做类似的事情,但不完全相同:你可以过滤(:exec!..| less)输入或输出,但不能同时过滤两者。看来我得自己写脚本了。 - John Quilder
如果你觉得这很方便(但我不这么认为),可以考虑为Linux内核贡献一些新的系统调用来实现它。然后修改相应的shell。参与自由软件运动! - Basile Starynkevitch
Basile,我的问题解决了:reptyr -s PID实现了我想要的功能,并且似乎足够可靠。 - John Quilder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接