【发布时间】:2010-07-20 09:10:56
【问题描述】:
我已经坚持了一段时间了。 假设我有一个如下所示的 C 程序。我希望能够向该程序发送一些字符串并在此之后获得控制权。 如果我这样做:
--> cat myfile |我的程序
或
--> echo "0123" |我的程序
或
--> 我的程序 我得到了输出(我的文件包含“0123”)
30 31 32 33
使用 -n 选项会引发段错误
--> echo -n mystring | 。/测试
zsh: 完成 echo -n "0123" |
zsh: 分段错误./test
我也尝试过使用命名管道,但也没有用。
我希望能够做类似的事情 猫我的文件 |我的程序 并取回控件,以便我可以输入其他字符。
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 int main (int argc, char *argv[]) {
6 int i = 0, j;
7 unsigned char buf[512];
8 unsigned char x;
9
10 while ((x = getchar()) != '\n') {
11 buf[i] = x;
12 i++;
13 }
14
16 for (j = 0; j < i; j++) {
17 printf("%x ", buf[j]);
18 }
19 printf ( "\n" );
20
21 return EXIT_SUCCESS;
22 } // end of function main
编辑:
下面是我想出的包装器。 它做了我想做的一切,除了子执行文件的输出没有正确显示。
没有包装器:
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
2+2
4
使用包装器:
$ ./wrapper bc
2+2
enter
4
删除行
dup2(pipefd[0], 0); // Set the read end of the pipe as stdin.
使子标准输出正确显示,但当然会破坏包装器。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <assert.h>
int main(int argc, char const *argv[]) {
int cpid;
int pipefd[2];
if (pipe(pipefd) == -1) { perror("pipe.\n"); exit(errno); }
cpid = fork();
if (cpid == -1) { perror("fork."); exit(errno); }
if (cpid) {
// Parent --------------------------------------------------------
int buf_size = 8192;
char buf[buf_size];
size_t file;
// Close the unused read end of the pipe.
close(pipefd[0]);
// Leave a bit of time to the child to display its initial input.
sleep(2);
while (1) {
gets(buf);
if (strcmp("enter", buf) == 0) {
write(pipefd[1], "\n", 1);
} else if (-1 != (file = open(buf, O_RDONLY))) {
// Dump the output of the file to the child's stdin.
char c;
while(read(file, &c, 1) != 0) {
switch(c) {
case '\n':
printf("(skipped \\n)");
break;
default:
printf("%c", c);
write(pipefd[1], &c, 1);
};
}
printf("\n");
} else {
// Dump input to the child's stdin, without trailing '\n'.
for (int i = 0; (buf[i] != 0); i++) {
write(pipefd[1], buf + i, 1);
}
}
}
// Wait for the child to exit.
printf("Waiting for child to exit.\n");
wait(NULL);
} else {
// Child ---------------------------------------------------------
// Close the unused write end of the pipe.
close(pipefd[1]);
// Set the read end of the pipe as stdin.
dup2(pipefd[0], 0); // Set the read end of the pipe as stdin.
char** program_arguments = (char**)(argv + 1);
if (execvp(argv[1], program_arguments) < 0) {
perror("execvp.\n");
exit(errno);
}
}
}
【问题讨论】:
-
echo -n 方法的段错误是因为您的第 10 行查找“\n”并将继续读取 RAM 直到找到。
-
“在那之后获得控制权”是什么意思?你的意思是程序必须在没有等待它完成的情况下进行读取(以及计算和输出)? (这样您以后所做的任何事情都可能与 myprogram 的输出混合在一起)...在这种情况下,您可以分叉(而 segfault 是由程序中的错误给出的,如前所述)
-
是的。但我不想要这种行为。当我说我想要控制权时,我的意思是我希望我的程序保持在 while(getchar() != '\n') 如果我给 "mystring\n" 作为输入它应该继续并终止,但是如果我只是给出“mystring”,程序仍应等待我的输入和一个 '\n' 字符。 (这就是我尝试使用 echo 的 -n 选项的原因。)
-
这里的不同行为是由于 bc.您可以使用“-i”标志运行 bc 以强制交互模式。然后很可能你会看到相同的输出。