linux下使用c语言模拟tail [-n] 命令

为了加深一下对linux下常规命令的理解顺带写作业,就用c语言模拟了一下tail命令。

首先简单介绍一下tali命令的用法。
tail test.txt:显示test.txt文件的最后十行
tail -n 5 test.txt:显示test.txt文件最后五行
当然tail命令还有tail -f 这个用法,用于实时更新文件的最后十行,不过为了偷懒就没写了,思路差不多,只是需要隔一段时间重新刷新一下。

同时,如果后面给的文件路径或者文件名等写错了,或者写的参数不正确,导致参数错误或文件找不到的话,也会有提示信息。

作为小白,下面写的内容只要会c语言基本语法就能看懂,不会的地方我均写了解释或者放上了参考文档。
这里写图片描述

废话不多说,开始讲解思路:

1、初始化默认读取长度line=10,如果使用了-n参数设置了长度为x,那么就让line=x

2、一行一行读取文件并保存在数组。但是我是模拟了一下循环数组,即当数组长度达到line了就将数组下一次写入的位置下标设置为0,这样在一定程度上保证了不会因为文件太大而溢出。
举个例子:假如文件一共15行,保存文件每一行数据的数组为char buffer[][],第0-9行存放在buffer[0][] - buffer[9][] 之中,但是第10行数据又会被保存到buffer[0][]中,因为最后只需要输出10行即可,所以只需要保存距离当前位置的最后十行。不过为了输出时候保证位置正确,肯定是要记录数组下标的。

3、开始输出了,输出是对buffer数组进行循环遍历,循环的次数等于min(line,文章行数)。
然后从前面保存的下标开始输出即可。

这里写图片描述

思路清晰了,就到了具体实现中存在的问题了。
首先,main函数的参数是什么意思?
请参考:http://blog.csdn.net/yhawaii/article/details/7361302
然后,既然需要读取-n 5 文件路径 这些信息,而且并不知道-n 5这样的参数是否会存在,如何解决?
请参考:https://www.cnblogs.com/qingergege/p/5914218.html
再之后,如何一行一行读取文件?
有两个思路,使用read,或者是用fgets。我们要求是使用read的,但是太麻烦了,我偷懒就还是使用fgets了。下面先简要介绍一下用read实现的思路:
想了解一下read的童鞋请参考:
这里写图片描述
read的配套用法——open详解
read的用法详解
1) 定义一个缓冲区,用read将文件全部存入缓冲区再通过\n来识别换行。明显的一个缺陷就是当文件太大的时候缓冲区会存不下,浪费了存储空间。
2) 每次读一个字符,然后保存到一个临时缓冲队列里,读取到第一个\n后将缓冲队列里的数据当成一行存储。缺点在于效率低下。
这两种思路是在一个论坛里总结出来的,论坛链接

总之使用read是很麻烦的一件事

,所以接下来还是老实使用fgets吧。
这个就很简单啦,参考:fgets读取文件

可运行源代码

最后就是我的源码咯,头文件可能多了点,因为原来使用read加上去的,但是嫌read太麻烦还是改成fgets了。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#define BUFFSIZE 512


int main(int argc,char **argv)
{
    char c;
    int line = 10;
    int count = 0;
    char buffer[BUFFSIZE][BUFFSIZE];

    //如果有-n,就将line的默认值改了。这里有错误默认是会自动提示的。
    while((c=getopt(argc,argv,"n:"))!=-1)
    {
        int x = atoi(optarg);
        line = x;
    }
    //获取文件路径,optind是某个头文件里的东西,不是我定义的,指示的是argv中下一个要读取的数据的下标
    char *path = argv[optind];


    FILE *fp;
    int index = 0;
    //如果文件打开不成功,肯定是文件没找到,就报错
    if((fp = fopen(path,"r")) == NULL)
    {
        printf("File dosen't exit!");
        return -1;
    }

    //下面就是前面讲的思路了,读取文件保存到数组
    while(!feof(fp))
    {
        count++;
        fgets(buffer[index],BUFFSIZE,fp);
        if(index+1 >= line)
        {
            index = 0;
        }
        else{
            index++;    
        }
    }

    //记得关闭fp
    fclose(fp);
    int i;
    if(count < line)
    {
        line = count;
    }
    //因为前面是用的++,多加了1
    if(index != 0)
    {
        index--;
    }
    for(i = 0;i<line;i++)
    {
        printf("%s",buffer[index++]);
        if(index >= line)
        {
            index = 0;
        }
    }

}

运行如图:
这里写图片描述

这里写图片描述

posted @ 2017-12-08 16:05  _吟游诗人  阅读(635)  评论(0编辑  收藏  举报