天天看點

linux下使用c語言模拟tail [-n] 指令

為了加深一下對linux下正常指令的了解順帶寫作業,就用c語言模拟了一下tail指令。

首先簡單介紹一下tali指令的用法。

​​

​tail test.txt​

​​:顯示test.txt檔案的最後十行

​​

​tail -n 5 test.txt​

​​:顯示test.txt檔案最後五行

當然tail指令還有​​

​tail -f​

​ 這個用法,用于實時更新檔案的最後十行,不過為了偷懶就沒寫了,思路差不多,隻是需要隔一段時間重新重新整理一下。

同時,如果後面給的檔案路徑或者檔案名等寫錯了,或者寫的參數不正确,導緻參數錯誤或檔案找不到的話,也會有提示資訊。

作為小白,下面寫的内容隻要會c語言基本文法就能看懂,不會的地方我均寫了解釋或者放上了參考文檔。

linux下使用c語言模拟tail [-n] 指令

廢話不多說,開始講解思路:

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,文章行數)。

然後從前面儲存的下标開始輸出即可。

linux下使用c語言模拟tail [-n] 指令

思路清晰了,就到了具體實作中存在的問題了。

首先,main函數的參數是什麼意思?

然後,既然需要讀取​

​-n 5 檔案路徑​

​ 這些資訊,而且并不知道​

​-n 5​

​這樣的參數是否會存在,如何解決?

再之後,如何一行一行讀取檔案?

有兩個思路,使用read,或者是用fgets。我們要求是使用read的,但是太麻煩了,我偷懶就還是使用fgets了。下面先簡要介紹一下用read實作的思路:

想了解一下read的童鞋請參考:

linux下使用c語言模拟tail [-n] 指令

​​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;
        }
    }

}      

運作如圖:

繼續閱讀