自己实现tail命令

操作系统
Published

May 9, 2018

这是linux系统编程手册中的题目。

代码

废话不多说直接上代码,虽然感觉还有个小bug。。

#include "tlpi_hdr.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <getopt.h>

#define BUFFSIZE 4096
char buf[BUFFSIZE] = {0};
int cntline = 0;   //用于计算已经读取的行数
int showline = 10; //默认是10
bool over = false;

int serchline(int fd, int pos)
{
    while (pos > BUFFSIZE)
    {
        pos = lseek(fd, -BUFFSIZE, SEEK_END); //如果文件长度大于4096,那么移动-4096字节开始读
        read(fd, buf, BUFFSIZE);
        for (int i = (BUFFSIZE - 1); i > 0; i--) //倒序访问
        {
            if (buf[i] == '\n')
            {
                cntline++;
            }
            if (cntline > showline) //如果读取到了10行
            {
                pos += i; //记录位置
                over = true;
                return pos;
            }
        }
        memset(buf,0,BUFFSIZE);//要清空一下数组
    }
    //执行到这里说明找了4096字节都没找到showline行,或者是文件本身就没有这么长
    lseek(fd, 0, SEEK_SET);       //那么从头开始读
    read(fd, buf, pos);           //读postion个字节
    for (int i = pos; i > 0; i--) //倒序访问
    {
        if (buf[i] == '\n')
        {
            cntline++;
            // printf("cntline : %d postion : %d \n", cntline, pos);  
        }
        if (cntline > showline) //如果读取到了showline行
        {
            pos = i; //记录位置
            over = true;
            return pos;
        }
    }
    memset(buf,0,BUFFSIZE);//要清空一下数组
    //执行到这里说明寻找结束也没有showline行
    return -1;
}

int main(int argc, char *argv[])
{
    int fd = -1;
    char ch;
    int postion = -1;
    int readsize=0;
    if (argc == 1)
    {
        usageErr("[ -n num ] filename \n to printf last num line of file\n");
    }
    while ((ch = getopt(argc, argv, "n:num")) != -1)
    {
        switch (ch)
        {
        case 'n':
            showline = atoi(optarg);
            break;
        default:
            usageErr("[ -n num ] filename \n to printf last num line of file\n");
            break;
        }
    }
    if (showline > 0)
    { //如果要显示大于0的行数
        if ((fd = open(argv[optind], O_RDONLY)) == -1)
        {
            errExit("open");
        }

        if ((postion = lseek(fd, 0, SEEK_END)) == -1) //先得出文件总长度
        {
            errExit("lseek");
        }
        // printf("file all length: %d\n", postion);
        postion = serchline(fd, postion);
        if (postion != -1)
            lseek(fd, postion, SEEK_SET); //说明找到了最后showline行
        do
        {
            readsize=read(fd, buf, BUFFSIZE);
            printf("%s",buf);
            memset(buf,0,BUFFSIZE);//输出完了就清空
        } while(readsize > BUFFSIZE);//输出所有
    }
    else
    {
        usageErr("[ -n num ] filename \n to printf last num line of file\n");
    }
    return 0;
}

总结

通过这个题目,学会了如何在vscode里面使用gdb: vscode自带的gdb调试不好使,还是要下载插件Native Debug才好使。我使用自带的gdb调试,第一句话就报错退出。但是我用上插件就没有问题了。