在 C 语言中同时管道输入标准输入和键盘



我也读过以前关于这个问题的问题。 fflush(stdin) 在这种情况下对我来说不起作用。 我希望我的程序从管道 stdin 读取,并从中间的键盘输入继续。

int main()
{
int userin = 3;
read_input();   
userin = print_menu();
userin = parse_input(userin);
return 0;
}  

我想从作为 pipied stding 传递给程序的文件中读取数据,例如

计划

int read_input(){
char line[200];
char word[MAX_STRING+1];
int line_number = 0;
while(fgets(line, sizeof(line), stdin) != NULL ){
//do something
printf("%s",line); 
line_number++;
}
}

现在read_input必须完成管道输入的读取。"print_menu"必须继续从键盘读取。

int print_menu()
{
int userinput;
char c;
char num[4];
while((c=getchar()) != 'n' && c != EOF && c != 'r');
printf("n1. Choice 1 n");
printf("2. Choice 2n");
printf("3. Exitn");
printf("Enter your choice (1-3): ");
/* scanf("%d", &userinput); */
/* fgets(num,80,stdin);  */
scanf("%s", num);
userinput = atoi(num);   
return userinput;
}
int parse_input(int userinput)
{
char num[4];
while( userinput > 3 || userinput < 1 ){
printf("Sorry, that is not a valid optionn");
printf("Enter your choice (1-3): ");
scanf("%s", num);
userinput = atoi(num);

/* scanf("%d", &userinput); */
/* while( (c = getchar()) == 'n'); */
}
return userinput;
}

我的输出是一个无限循环

Enter your choice (1-3): Sorry, that is not a valid option

当我删除read_input方法和管道 stdin 程序工作正常时。 我想不通解决这个问题的方法,有人有想法吗..

管道(由shell控制)通常出现在文件描述符0上,这是标准输入。 您可以使用dup2()将其"移动"到其他文件描述符,并使用freopen()继续从中读取。 您还可以打开/dev/tty设备(或tty程序知道的任何内容)并将其作为标准输入。

对话框程序对--gauge(进度条)选项执行此操作。 它这样做的原因是对话框是一个curses应用程序(默认情况下使用标准输入和输出)。 实际的管道文件描述符也是可选的,因此引用其手册页给出了一些提示:

--

输入-FDFD

从给定的文件描述符读取键盘输入。 大多数对话框脚本从标准输入读取,但仪表小组件读取 管道(始终是标准输入)。 某些配置可以 对话框尝试重新打开终端时无法正常工作。 用 此选项(适当处理文件描述符)如果 脚本必须在该类型的环境中工作。

实现这一点的逻辑在util.c中,来自init_dialog函数。 这是其中的主要部分,以说明如何使用这些函数:

dialog_state.pipe_input = stdin;
if (fileno(input) != fileno(stdin)) {
if ((fd1 = dup(fileno(input))) >= 0
&& (fd2 = dup(fileno(stdin))) >= 0) {
(void) dup2(fileno(input), fileno(stdin));
dialog_state.pipe_input = fdopen(fd2, "r");
if (fileno(stdin) != 0)     /* some functions may read fd #0 */
(void) dup2(fileno(stdin), 0);
} else {
dlg_exiterr("cannot open tty-input");
}
close(fd1);
} else if (!isatty(fileno(stdin))) {
if ((fd1 = open_terminal(&device, O_RDONLY)) >= 0) {
if ((fd2 = dup(fileno(stdin))) >= 0) {
dialog_state.pipe_input = fdopen(fd2, "r");
if (freopen(device, "r", stdin) == 0)
dlg_exiterr("cannot open tty-input");
if (fileno(stdin) != 0)         /* some functions may read fd #0 */
(void) dup2(fileno(stdin), 0);
}
close(fd1);
}
free(device);
}

我编写的程序几乎相同,该程序用于从stdin读取二进制数据(从其他程序的stdout管道传入),但我想添加键盘命令(通过原始终端支持)。 显然,同时读取管道数据和键盘会导致一些奇怪的结果。

这是我的代码,工作和测试:

文件 * fp; 国际 FD; fd = dup(fileno(stdin)); fp = fdopen(fd, "r"); (void) freopen("/dev/tty", "r", stdin);

现在,我的程序从 fp(一个FILE*对象)读取其二进制数据,同时读取stdin(现在与"/dev/tty"相关联)的击键。

请注意,我丢弃了freopen(FILE*对象)的返回值,因为如果需要,我可以通过stdin引用它。 我的经验是,无需close()fclose()标准文本流。 我在读取二进制数据结束时fclose(fp)

如果希望程序接受键盘输入,请不要重定向其标准输入。 如果重定向程序的标准输入,请不要期望能够通过键盘向其提供数据。

如果程序需要同时接受来自文件和键盘的输入,则为其提供文件名作为参数,并让它打开并读取该文件。

如果您必须处理某种不可修改的库函数,该函数需要通过stdin提供输入,并且您希望该输入来自文件,并且您希望其他地方接受键盘输入,那么您可以使用dup2()ing 文件描述符玩游戏以使其正常工作。 一旦你让它工作,考虑解雇负责该库函数的白痴。

最新更新