我试图与一个进程通信(该进程本身会写入stdin和stdout,以便在终端中与用户交互),并在C中读取它的stdin和写入它的stdout。
因此,我尝试以编程方式替换shell用户。一个methapohrical示例:假设出于某种原因我想在C中使用VIM。然后我还需要编写命令(stdout)并从编辑器(stdin)中读取内容。
起初我认为这可能是一项微不足道的任务,但似乎没有标准的方法<代码>int系统(const char*命令) 只执行一个命令,并将命令stdin/stdout设置为调用进程之一。
因为这毫无意义,我查看了FILE*popen(constchar*命令,constchar*类型)
但手册页面说明:
由于管道根据定义是单向的,所以类型参数可以只指定读取或写入,而不是两者都指定;相应地,结果流是只读或只写的。
及其含义:
popen()的返回值在所有方面都是正常的标准I/O流,但它必须使用pclose()而不是fclose(3)关闭。写入这样的流写入命令的标准输入;该命令的标准输出与调用popen()的进程的标准输出相同,除非命令本身对此进行了更改。相反,从“popend”流读取命令的标准输出,命令的标准输入与调用popen()的进程的标准输入相同。
因此,使用popen()并非完全不可能,但在我看来它非常不雅观,因为我必须解析调用进程的stdout(调用popen()的代码),以便解析从popened命令发送的数据(当使用popen类型“w”时)。
相反,当使用“r”类型调用popen时,我需要写入调用的进程stdin,以便将数据写入popened命令。在本例中,我甚至不清楚这两个进程是否在stdin中接收相同的数据。。。
我只需要控制程序的stdin和stdout。我的意思是,难道不能有这样一个函数:
stdin_of_process, stdout_of_process = real_popen("/path/to/bin", "rw")
// write some data to the process stdin
write("hello", stdin_of_process)
// read the response of the process
read(stdout_of_process)
所以我的第一个问题是:实现上层功能的最佳方式是什么?
目前,我正在尝试以下方法与另一个进程进行通信:
用int-pipe(int-fildes[2])设置两条管道
。一个管道读取进程的标准输出,另一个管道写入进程的标准输入
叉子
使用intexecvp(constchar*file,char*constargv[]),在分叉子进程中执行我想要与之通信的进程
使用原始流程中的两个管道与子级进行通信
这很容易,机器人不是那么简单地实现的(至少对我来说)。在一个案例中,我奇怪地设法做到了这一点,但是当我试图用一个更简单的例子来理解我在做什么时,我失败了。这是我目前的问题:
我有两个节目。第一个只需每隔100毫秒将递增的数字写入其标准输出:
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
void sleepMs(uint32_t ms) {
struct timespec ts;
ts.tv_sec = 0 + (ms / 1000);
ts.tv_nsec = 1000 * 1000 * (ms % 1000);
nanosleep(&ts, NULL);
}
int main(int argc, char *argv[]) {
long int cnt = 0;
char buf[0x10] = {0};
while (1) {
sleepMs(100);
sprintf(buf, "%ld\n", ++cnt);
if (write(STDOUT_FILENO, buf, strlen(buf)) == -1)
perror("write");
}
}
现在,第二个程序应该读取第一个程序的stdout(请记住,我最终想要读取和写入一个进程,所以在上面的用例中使用popen()的技术正确解决方案可能是正确的具体情况下,因为我简化了我的实验,只是捕获底层程序的stdout)。我希望从底层程序读取上层程序写入stdout的任何数据。但它什么也不读。原因在哪里?(第二个问题)。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
void sleepMs(uint32_t ms) {
struct timespec ts;
ts.tv_sec = 0 + (ms / 1000);
ts.tv_nsec = 1000 * 1000 * (ms % 1000);
nanosleep(&ts, NULL);
}
int main() {
int pipe_fds[2];
int n;
char buf[0x100] = {0};
pid_t pid;
pipe(pipe_fds);
char *cmd[] = {"/path/to/program/above", NULL};
if ((pid = fork()) == 0) { /* child */
dup2(pipe_fds[1], 1); // set stdout of the process to the write end of the pipe
execvp(cmd[0], cmd); // execute the program.
fflush(stdout);
perror(cmd[0]); // only reached in case of error
exit(0);
} else if (pid == -1) { /* failed */
perror("fork");
exit(1);
} else { /* parent */
while (1) {
sleepMs(500); // Wait a bit to let the child program run a little
printf("Trying to read\n");
if ((n = read(pipe_fds[0], buf, 0x100)) >= 0) { // Try to read stdout of the child process from the read end of the pipe
buf[n] = 0; /* terminate the string */
fprintf(stderr, "Got: %s", buf); // this should print "1 2 3 4 5 6 7 8 9 10 ..."
} else {
fprintf(stderr, "read failed\n");
perror("read");
}
}
}
}
您的想法是正确的,我没有时间分析您的所有代码来指出具体的问题,但我确实想指出一些您在程序和终端如何工作方面可能忽略的事情。
终端作为“文件”的想法是幼稚的。像vi这样的程序使用一个库(ncurses)来发送特殊的控制字符(并更改终端设备驱动程序设置)。例如,vi将终端设备驱动程序本身置于一种模式,在这种模式下,它可以一次读取一个字符,等等。
以这种方式“控制”像vi这样的程序是非常重要的。
在你的简化实验中...
缓冲区太小一个字节。另外,请注意IO有时是行缓冲的。因此,您可以尝试确保换行符正在被传输(使用printf而不是斯普林特/斯特伦/写...您已经将stdout挂接到管道上了),否则您可能在换行符被命中之前看不到数据。我不记得管道有线路缓冲,但值得一试。
这是一个(C 11风味)完整的例子。
但是,出于许多实际目的,Expect库可能是一个不错的选择(请查看其源代码发行版的example
子目录中的代码)。
问题内容: 这是此问题的后续措施,但是如果我想将参数传递给,如何实时获取输出?这就是我目前拥有的;我也尝试从模块中替换为,这只会导致脚本挂起。 在我不必通过的前一个问题中,建议我使用,没有空间输送任何东西到。 附录:这适用于传输,但是我只能在最后看到输出,并且我想查看传输发生时的详细信息。 问题答案: 为了实时从子流程中获取标准输出,您需要准确确定所需的行为;具体来说,您需要确定是要逐行处理还是逐
问题内容: (我是Java新手)我需要启动一个进程并接收2或3个句柄:对于STDIN,STDOUT(和STDERR),因此我可以将输入写入进程并接收其输出,就像命令行管道一样表现(例如“ grep”) 在Python中,可以通过以下代码实现: Java等效项是什么? 到目前为止我已经尝试过 顺便说一句,第一次尝试仅适用于\ n \ n,但不适用于单个\ n(为什么?) 下面的代码有效,但是所有输入
问题内容: 我试图从通话中抢夺,尽管我可以通过以下方式轻松实现此目标: 我想“实时”抓取。使用上述方法,PIPE等待获取所有内容,然后返回。 因此,出于日志记录目的,这不符合我的要求(例如,“查看”发生的情况)。 在运行时,有没有办法逐行获取?或者这是(必须等到关闭)的限制。 编辑 如果我切换为我只得到(不理想)的最后一行: 问题答案: 您的解释器正在缓冲。在打印语句后,添加对sys.stdout
问题内容: 我试图在Python中使用子进程,以使外部脚本以类似于服务器的方式打开。外部脚本首先加载模型。完成此操作后,它将通过STDIN接受请求,并将处理后的字符串返回给STDOUT。 到目前为止,我已经尝试过 但是,我不能使用 为了通过子过程重复处理input_strings,无论我使用还是,out都将是空的。但是,当我在读取STDOUT之前关闭stdin时,它起作用了,但是这关闭了子进程,这
我有一个程序,通过Pipe. SourceChannel将stdout、stderr和stdin传输到/从Bytes Buffers。 程序使用选择器注册每个通道。 循环中的程序定期遍历 selectedKeys 集中的每个键,这些键对应于 stdout、stderr 和 stdin。对于每个密钥,它确定密钥是否有效、可读或可写,如果是,则与 ByteBuffer 执行相应的 IO 操作 我的问题
问题内容: 我想捕获并显示通过Python的子流程调用的流程的输出。 我以为我可以将文件状对象作为参数stdout和stderr传递 我可以看到它访问了属性-因此它正在处理对象。但是,永远不会调用该方法。我的方法是否完全无效或我只是缺少什么? 更新: 我还想工作的是ANSI控制字符,用于移动光标并覆盖以前的输出内容。我不知道这是否是正确的术语,但这是我的意思的一个示例:我正在尝试使一些GIT自动化