Linux系统编程之实现more命令
Linux系统编程之实现more命令
在学习内核以及内核编程的间隙,会时不时进⾏⼀些系统编程的练习,来更好的理解操作系统,边分析操作系统的职责,同时动⼿练习编写⼀些与操作系统紧密相连的程序,⽬的在于最终可编写实现⾃⼰意图功能的程序。
系统编程与内核编程的不同?
系统编程可以说是操作系统提供给⽤户程序的⼀组“特殊”接⼝,⽤户程序可以通过这组特殊的接⼝来获得操作系统内核提供的。在linux中⽤户程序不能直接访问内核提供的服务,为了更好的保护内核,将程序的运⾏空间分为内核空间和⽤户空间,他们运⾏在不同的级别上。
系统编程所使⽤的系统调⽤,或是说linux给予可供调⽤的系统资源?
处理器、输⼊输出(I/O)、进程管理、内存、设备、计时器、进程间通信、⽹络。
此次编写第⼀个命令的实现:more
more命令的作⽤
与cat类似,浏览⽂件内容,但是more为分页查看,最基本的指令为在分页浏览的时候
space:显⽰下⼀页内容
enter:显⽰下⼀⾏
q:结束显⽰
h:联机帮助
在屏幕底部⽤反⽩字体显⽰⽂件百分⽐
more命令⽤法
more filename
command | more
more < filename
###main函数
#include <stdio.h>
#define PAGELEN 24
#define LINELEN 512
void do_more(FILE *);
int see_more();
int main(int ac ,char *av[])
{
FILE *fp;
if (ac == 1)
do_more(stdin);
else
while (--ac)
if ((fp = fopen(* ++av,"r"))!= NULL)  /* av ac??*/
{
do_more(fp);
fclose(fp);
}
else
exit(1);
return 0;
linux重定向}
main函数的意图⽐较明确,⼀个选择分⽀结构,其中具体的参数问题解释见。
若main函数执⾏只有⼀个参数,则意味着⽆⽂件,那么把键盘输⼊到缓冲区⾥的数据⽤do_more函数读出来。
若有多个参数,则执⾏读⽂件时候的⽅法,即当⽤只读⽅式打开指针数组所指向的⽂件地址内容不为空时,do_more显⽰⽂件内容,⽽所指向地址为空时退出当前进程。
do_more函数与see_more函数
void do_more(FILE *fp)
{
char line [LINELEN];
int num_of_lines =0;
int see_more(),reply;
while(fgets(line,LINELEN,fp))
{
if(num_of_lines==PAGELEN)
{
reply =see_more();
if(reply==0)
break;
num_of_lines -=reply;
}
if(fputs(line,stdout) ==EOF)
exit(1);
num_of_lines++;
}
此函数的作⽤是使⽤fgets函数从所传递过来的⽂件中⼀⾏⾏读取数据,当屏幕满了时,调⽤see_more函数,做出相应处理,最终当输出的字符串为⽂件结尾时退出当前进程。
int see_more()
{
int c;
printf("\033[7m more?\033[m");
while ((c=getchar()!=EOF))
{
if(c=='q')
return 0;
if(c==' ')
return PAGELEN;
if(c=='\n')
return 1;
}
return 0;
}
⾄于相应处理,就是由see_more来控制,也就是之前提到的more命令中的相应命令,当然不能忘记反⽩的字体‘more?’若从键盘输⼊q则返回值为0,在do_more⾥break
若从键盘输⼊空格,则返回⾏数,do_more中把⾏数重置为0,再显⽰接下来的⽂件。
若从键盘输出回车,则返回1,do_more中⾏数只减1,那么只多显⽰1⾏。
看起来我们完成了!那么来试试它的效果
#include <stdio.h>
#define PAGELEN 24
#define LINELEN 512
void do_more(FILE *);
int see_more();
int main(int ac ,char *av[])
{
FILE *fp;
if (ac == 1)
do_more(stdin);
else
while (--ac)
if ((fp = fopen(* ++av,"r"))!= NULL)  /* av ac??*/
{
do_more(fp);
fclose(fp);
}
else
exit(1);
return 0;
}
more?
more?
void do_more(FILE *fp)
more?
{
more?
char line [LINELEN];
int num_of_lines =0;
int see_more(),reply;
while(fgets(line,LINELEN,fp))
{
if(num_of_lines==PAGELEN)
{
reply =see_more();
if(reply==0)
break;
num_of_lines-=reply;
}
重定向数据源问题
看起来虽然有些⼩瑕疵,但是效果还⾏,可是有⼀个很关键的问题就是当我们的数据来源不是⽂件,⽽是管道重定向的时候,就有些问题了。
bash
brltty
bunzip2
busybox
bzcat
bzcmp
bzdiff
bzegrep
bzexe
bzfgrep
bzgrep
bzip2
bzip2recover
bzless
bzmore
cat
chacl
chgrp
chmod
chown
chvt
cp
cpio
dash
more?date
more?df
more?dmesg
more?domainname
more?echo
more?efibootdump
more?egrep
more?fgconsole
more?findmnt
more?fusermount
more?grep
more?gzexe
more?hciconfig
more?ip
more?kbd_mode
more?kmod
可以看到,当数据来源为这种时候,它输出了24⾏但是并没有停下⽽是全部输出完了,这是为什么呢?
分析问题可以看到在see_more函数中,需要我们输⼊字符来进⾏下⾯的操作,但若我们使⽤的是管道重定向或输⼊重定向的话,就不会请求我们输⼊了,因为getchar()这个函数是读取标准输⼊的数据,现在我们⽤管道重定向或输⼊重定向将标准输⼊重定向了,所以getchar()函数会直接读取ls /bin这个命令输出。
如何解决这个问题呢?
我们可否把所有数据从标准输⼊读⼊,然后直接从键盘读⽤户的输⼊,也就是说把这两种数据流分开。Linux中有⼀个⽂件/dev/tty,此⽂件是显⽰器与键盘的描述⽂件,向这个⽂件写相当于显⽰在⽤户屏幕,读相当于从键盘获取⽤户输⼊,我们可以有效使⽤这⼀点,那么我们只需要改⼀下少量的do_more与see_more。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。