• 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将文件全部存入缓冲区再通过 来识别换行。明显的一个缺陷就是当文件太大的时候缓冲区会存不下,浪费了存储空间。
    2) 每次读一个字符,然后保存到一个临时缓冲队列里,读取到第一个 后将缓冲队列里的数据当成一行存储。缺点在于效率低下。
    这两种思路是在一个论坛里总结出来的,论坛链接

    总之使用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;
            }
        }
    
    }
    

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

    这里写图片描述

  • 相关阅读:
    mysql缓存
    复杂映射
    SQL 映射的 XML 文件
    xml配置文件
    从xml中构建sqlSessionFactory
    eclipse使用时jar不在libraries
    去掉不用的工作空间
    javac找不到或无法加载主类 com.sun.tools.javac.Main,
    文本,布局,样式
    (常用)re模块
  • 原文地址:https://www.cnblogs.com/yinyoupoet/p/13287556.html
Copyright © 2020-2023  润新知