| 
 | 
地板
 
 
 楼主 |
发表于 2009-3-4 11:07:04
|
只看该作者
 
 
 
与终端对话(Talking to the terminal)
如果你需要阻止你程序中与用户交互的那部分不被重定向,但仍允许其作用在其他的输入或输出上,你需要把交互部分与 stdout 和 stderr 分开。你可以通过直接读写终端来做到这一点。因为 linux 天生就是一个多任务系统,经常有许多终端对其直连或通过网络连接 ,那我们如何才能发现有正确的终端可用呢? 
 
幸运的是, linux 和 UNIX 通过提供一个特殊的设备 -- /dev/tty(这总是当前终端或登录会话),使这件事情变得容易。因为 linux 对所有的东西都认为是一个文件,所以你可以使用操作普通文件的方法来读写 /dev/tty。 
 
测试程序: 
 01 #include <stdio.h> 
02 #include <unistd.h> 
03 #include <stdlib.h> 
04  
05 char *menu[] = { 
06         "a - add new record", 
07         "d - delete record", 
08         "q - quit", 
09         NULL, 
10         }; 
11  
12 int getchoice(char *greet, char *choices[], FILE *in, FILE *out); 
13  
14 int main() 
15 { 
16         int choice = 0; 
17         FILE *input; 
18         FILE *output; 
19  
20         if(!isatty(fileno(stdout))) { 
21                 fprintf(stderr, "you are not a terminal, OK.\\n"); 
22         } 
23  
24         input = fopen("/dev/tty", "r"); 
25         output = fopen("/dev/tty", "w"); 
26         if(!input || !output) { 
27                 fprintf(stderr, "Unable to open /dev/tty\\n"); 
28                 exit(1); 
29         } 
30  
31         do { 
32                 choice = getchoice("Please select an action", menu, input, output); 
33                 printf("You have chosen: %c\\n", choice); 
34         } while(choice != 'q'); 
35         exit(0); 
36 } 
37  
38 int getchoice(char *greet, char *choices[], FILE *in, FILE *out) 
39 { 
40         int chosen = 0; 
41         int selected; 
42         char **option; 
43  
44         do { 
45                 fprintf(out, "Choice: %s\\n", greet); 
46                 option = choices; 
47  
48                 while(*option) { 
49                         fprintf(out, "%s\\n", *option); 
50                         option++; 
51                 } 
52  
53          do { 
54                 selected = fgetc(in); 
55         } while(selected == '\\n'); 
56  
57         option = choices; 
58  
59         while(*option) { 
60                 if(selected == *option[0]) { 
61                         chosen = 1; 
62                         break; 
63                 } 
64                 option++; 
65         } 
66         if(!chosen) { 
67                 fprintf(out, "Incorrect choice, select again\\n"); 
68         }  
69  
70         }while(!chosen); 
71  
72         return selected; 
73 }  运行输出:[root@localhost C]# ./menu-2.exe > file 
you are not a terminal, OK. 
Choice: Please select an action 
a - add new record 
d - delete record 
q - quit 
almq    #输入内容 
Choice: Please select an action 
a - add new record 
d - delete record 
q - quit 
Incorrect choice, select again 
Choice: Please select an action 
a - add new record 
d - delete record 
q - quit 
Incorrect choice, select again 
Choice: Please select an action 
a - add new record 
d - delete record 
q - quit 
[root@localhost C]# cat file 
You have chosen: a 
You have chosen: q  在“运行输出”中可以看到,错误的选项输入返回的提示会直接显示出来;而正确的选项输入则被重定向到了文件 file 中。 
这是因为,如果是错误的选项输入,那么经由 fprintf(out, "Incorrect choice, select again\\n"); 这个语句可以知道,输出被强制从当前的tty中输出;而正确的输入选项,则会经由 ./menu-2.exe > file 重定向到文件 file 中。 
 
注意,在 
 20         if(!isatty(fileno(stdout))) { 
21                 fprintf(stderr, "you are not a terminal, OK.\\n"); 
22         }  中,这用来判断当前的标准输出是否连接一个终端上。可以做这么一个实验: 
 
如果是在 linux 的桌面环境下开启的一个终端窗口,那么就会打印出: 
you are not a terminal, OK 
字样,表明当前的标准输出窗口不是一个终端。 
 
如果在 windows 中用如 putty 这样的一个连接工具进行 ssh 连接到 linux 中,则这个提示不会出现,因为那样的连接方式所对的客户机就认为是一个终端。 |   
 
 
 
 |