More命令
more命令一般用于分页显示文件的内容,more会显示文件第一屏的内容,在屏幕的底部,more用反白字体显示文件的百分比,这时如果按空格键,文件下一屏内容会显示出来,如果按回车键,显示的则是下一行,如果输入“ q ”,则是结束显示。
more命令的几种用法
第一种:
$ more filename
显示文件filename的内容。
自由互联热门推荐:PDF电子发票识别软件,一键识别电子发票并导入到Excel中!10大顶级数据挖掘软件!人工智能的十大作用!
第二种:
$ command | more
将command命令的输出分页显示。
第三种:
$ more < filename
从标准输入获取要分页显示的内容,而这时more的标准输入被重定向到文件filename。
more命令的工作流程
+———–> 显示24行
| +——> 输入操作,打印信息
| | 可以输入回车键、空格键、q键
| +——> 输入回车键,打印一行
+ ———> 如果空格键,打印24行
如果是q键 —> 退出
more命令的编写—版本1
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define PAGELEN 24 5 #define LINELEN 512 6 7 void do_more(FILE *); 8 int see_more(); 9 10 int main(int ac,char *av[]) 11 { 12 13 FILE *fp; 14 if(ac == 1) 15 do_more(stdin); 16 else 17 while(--ac) 18 if((fp = fopen(* ++av,"r")) != NULL) 19 { 20 do_more(fp); 21 fclose(fp); 22 } 23 else 24 exit(1); 25 26 return 0; 27 } 28 29 30 void do_more(FILE *fp) 31 { 32 char line[LINELEN]; 33 int num_of_lines = 0; 34 int see_more(),reply; 35 36 while(fgets(line, LINELEN,fp)) 37 { 38 if(num_of_lines == PAGELEN) 39 { 40 reply = see_more(); 41 42 if(reply == 0) 43 break; 44 45 num_of_lines -= reply; 46 } 47 if(fputs(line,stdout) == EOF) 48 exit(1); 49 50 num_of_lines++; 51 } 52 } 53 54 int see_more() 55 { 56 int c; 57 printf("\033[7m more?\033[m"); 58 while((c = getchar()) != EOF) 59 { 60 if(c == 'q') 61 return 0; 62 if(c == ' ') 63 return PAGELEN; 64 if(c == '\n') 65 return 1; 66 67 } 68 return 0; 69 }
fopen 打开文件,打开成功返回一个指向该文件的文件指针,失败返回NULL。
fgets 从指定的文件中获取数据,每次读一行,并存入指定的buffer中最多读size – 1个
fputs 把字符串输出到stram中,但不输出空字符。发生错误,则输出EOF
getchar 从标准输入获取一个字符,相当于getc(stdin)
more版本1的问题:
1.当屏幕上的文字上滚时,[ more ]字符也会随之上滚,
2.当我们按下空格或者 “q” 后,如果没有按下回车,程序没有任何反应。
自己编写的more命令分析
我们首先使用linux自带的more命令
$ ls /bin | more
很明显,我们想做的是将/bin 目录下的文件分页显示,在使用 “ | ”管道命令把 ls 的输出重定向到 more的输入,并且等待我们输入命令,结果是令人满意的。
我们再使用自己编写的more命令
$ls /bin | more_v1
发现和linux自带的more命令非常的不同,我们自己编写的more并没有等待我们输入命令,而是一溜烟全部显示出来了,那么到底是什么问题呢?
其实很简单,问题出在getchar这个函数上,这个函数是从标准输入中获取字符的,然而,我们ls命令的输出已经重定向到标准输入了,意味着getchar和ls共用一个数据流,所以我们自己编写的more命令才会没有等待我们输入命令,而一下子全部打印了出来。
关于流,网上有很多解释,我看了但是依旧不是太理解,我自己画了一个图,也表达了我对流的理解,一个文件与另一个文件进行数据的传输,我认为这就是一个流。共用一个流就是两个文件都与一个文件同时传输数据。
这下找到了问题的根源,也就是说getchar不适用与more命令中,我们需要更改more。意味着我们需要把getchar的输入换成一个独立的流,
more命令的编写—版本2
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define PAGELEN 24 5 #define LINELEN 512 6 7 void do_more(FILE *); 8 int see_more(FILE *); 9 10 int main(int ac,char *av[]) 11 { 12 13 FILE *fp; 14 if(ac == 1) 15 do_more(stdin); 16 else 17 while(--ac) 18 if((fp = fopen(* ++av,"r")) != NULL) 19 { 20 do_more(fp); 21 fclose(fp); 22 } 23 else 24 exit(1); 25 26 return 0; 27 } 28 29 30 void do_more(FILE *fp) 31 { 32 char line[LINELEN]; 33 int num_of_lines = 0; 34 int reply; 35 FILE *fp_tty; 36 fp_tty = fopen("/dev/tty","r"); 37 if(fp_tty == NULL) 38 exit(1); 39 40 while(fgets(line, LINELEN,fp)) 41 { 42 if(num_of_lines == PAGELEN) 43 { 44 reply = see_more(fp_tty); 45 46 if(reply == 0) 47 break; 48 49 num_of_lines -= reply; 50 } 51 if(fputs(line,stdout) == EOF) 52 exit(1); 53 54 num_of_lines++; 55 } 56 } 57 58 int see_more(FILE *cmd) 59 { 60 int c; 61 printf("\033[7m more?\033[m"); 62 while((c = getc(cmd)) != EOF) 63 { 64 if(c == 'q') 65 return 0; 66 if(c == ' ') 67 return PAGELEN; 68 if(c == '\n') 69 return 1; 70 71 } 72 return 0; 73 }
第二个版本中使用了 /dev/tty 这个设备文件,向这个文件写相当于显示在用户的屏幕上,向这个文件读相当于从键盘中获取用户输入。这样我们的程序就拥有两个流, “ls” 的输出,将其分页显示到屏幕上,当more需要用户输入时,从 /dev/tty得到数据。
第二个版本仍然有more字符被打印到输出上、按下空格或者Q键还需要额外按下回车、无法根据中断大小来决定显示行数、无法文件已显示的百分比,这些问题有涉及到与终端类有关,我暂时读到这里,以后慢慢补充
—————–上文在 2019/4/30 记录——————-
本篇笔记自拜读《 Unix/Linux编程实践教程》
我也推荐和我一样的初学者去拜读这本书,让你对linux有可下手的地方。