在 C 中同时通过管道传输标准输入和键盘
piped stdin and keyboard same time in C
我也阅读了之前关于这个问题的问题。 fflush(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 2\n");
printf("3. Exit\n");
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 option\n");
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
、 和 提供输入,您希望该输入来自文件, 和 你想在别处接受键盘输入,那么你也许可以玩 dup2()
ing 文件描述符的游戏来让它工作。一旦你开始工作,考虑解雇负责该库函数的白痴。
管道(由 shell 控制)通常在文件描述符 0
上,这是标准输入。你可以使用 dup2()
to "move" that to a different file descriptor, and use freopen()
to continue reading from that. You can also open the /dev/tty
device (or whatever the tty
program knows about) 并使 that 你的标准输入。
dialog program does this for the --gauge
(progress bar) option. The reason why it does this is because dialog is a curses application (which by default uses the standard input and output). The actual pipe file-descriptor is as well optional, so quoting from its manual page给出了一些提示:
--input-fd fd
Read keyboard input from the given file descriptor. Most dialog
scripts read from the standard input, but the gauge widget reads
a pipe (which is always standard input). Some configurations do
not work properly when dialog tries to reopen the terminal. Use
this option (with appropriate juggling of file-descriptors) if
your script must work in that type of environment.
实现此功能的逻辑在 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
管道输入)的程序有相同的情况,但我想添加键盘命令(通过raw terminal support)。显然,同时读取管道数据和键盘会导致一些奇怪的结果。
这是我的代码,可以运行并经过测试:
FILE * fp;
int fd;
fd = dup(fileno(stdin));
fp = fdopen(fd, "r");
(void) freopen("/dev/tty", "r", stdin);
现在,我的程序从 fp(一个 FILE*
对象)读取其二进制数据,同时读取 stdin
(现在与 "/dev/tty"
相关联)以获得击键。
请注意,我丢弃了 freopen
(FILE*
对象)中的 return 值,因为如果需要,我可以通过 stdin
引用它。我的经验是不需要 close()
或 fclose()
标准文本流。我fclose(fp)
读取二进制数据结束。
我也阅读了之前关于这个问题的问题。 fflush(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 2\n");
printf("3. Exit\n");
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 option\n");
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 方法时,管道标准输入程序工作正常。
我不知道解决这个问题,有人有想法吗..
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 2\n");
printf("3. Exit\n");
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 option\n");
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
、 和 提供输入,您希望该输入来自文件, 和 你想在别处接受键盘输入,那么你也许可以玩 dup2()
ing 文件描述符的游戏来让它工作。一旦你开始工作,考虑解雇负责该库函数的白痴。
管道(由 shell 控制)通常在文件描述符 0
上,这是标准输入。你可以使用 dup2()
to "move" that to a different file descriptor, and use freopen()
to continue reading from that. You can also open the /dev/tty
device (or whatever the tty
program knows about) 并使 that 你的标准输入。
dialog program does this for the --gauge
(progress bar) option. The reason why it does this is because dialog is a curses application (which by default uses the standard input and output). The actual pipe file-descriptor is as well optional, so quoting from its manual page给出了一些提示:
--input-fd fd
Read keyboard input from the given file descriptor. Most dialog scripts read from the standard input, but the gauge widget reads a pipe (which is always standard input). Some configurations do not work properly when dialog tries to reopen the terminal. Use this option (with appropriate juggling of file-descriptors) if your script must work in that type of environment.
实现此功能的逻辑在 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
管道输入)的程序有相同的情况,但我想添加键盘命令(通过raw terminal support)。显然,同时读取管道数据和键盘会导致一些奇怪的结果。
这是我的代码,可以运行并经过测试:
FILE * fp; int fd; fd = dup(fileno(stdin)); fp = fdopen(fd, "r"); (void) freopen("/dev/tty", "r", stdin);
现在,我的程序从 fp(一个 FILE*
对象)读取其二进制数据,同时读取 stdin
(现在与 "/dev/tty"
相关联)以获得击键。
请注意,我丢弃了 freopen
(FILE*
对象)中的 return 值,因为如果需要,我可以通过 stdin
引用它。我的经验是不需要 close()
或 fclose()
标准文本流。我fclose(fp)
读取二进制数据结束。