ubuntu 編寫自己的ls命令


 

ls 命令可以說是Linux下最常用的命令之一。它有眾多的選項,其中有很多是很有用的,你是否熟悉呢?要學習如何編寫 ls 命令,首先我們要先了解它怎么使用。

我們在 Linux常用命令和vi,gdb的使用 第一節中就已經提到過 ls 命令的使用,下面我們先就 ls 命令做詳細的介紹

1.ls命令詳細介紹

下面列出了 ls 命令的絕大多數選項。   
  -a 列出目錄下的所有文件,包括以 . 開頭的隱含文件。 
  -b 把文件名中不可輸出的字符用反斜杠加字符編號(就象在C語言里一樣)的形式列出。 
  -c 輸出文件的 i 節點的修改時間,並以此排序。 
  -d 將目錄象文件一樣顯示,而不是顯示其下的文件。 
  -e 輸出時間的全部信息,而不是輸出簡略信息。 
  -f -U 對輸出的文件不排序。 
  -g 無用。 
  -i 輸出文件的 i 節點的索引信息。 
  -k 以 k 字節的形式表示文件的大小。 
  -l 列出文件的詳細信息。 
  -m 橫向輸出文件名,並以“,”作分格符。 
  -n 用數字的 UID,GID 代替名稱。 
  -o 顯示文件的除組信息外的詳細信息。 
  -p -F 在每個文件名后附上一個字符以說明該文件的類型,“*”表示可執行的普通 
  文件;“/”表示目錄;“@”表示符號鏈接;“|”表示FIFOs;“=”表示套 
  接字(sockets)。 
  -q 用?代替不可輸出的字符。 
  -r 對目錄反向排序。 
  -s 在每個文件名后輸出該文件的大小。 
  -t 以時間排序。 
  -u 以文件上次被訪問的時間排序。 
  -x 按列輸出,橫向排序。 
  -A 顯示除 “.”和“..”外的所有文件。 
  -B 不輸出以 “~”結尾的備份文件。 
  -C 按列輸出,縱向排序。 
  -G 輸出文件的組的信息。 
  -L 列出鏈接文件名而不是鏈接到的文件。 
  -N 不限制文件長度。 
  -Q 把輸出的文件名用雙引號括起來。 
  -R 列出所有子目錄下的文件。 
  -S 以文件大小排序。 
  -X 以文件的擴展名(最后一個 . 后的字符)排序。 
  -1 一行只輸出一個文件。 
  --color=no 不顯示彩色文件名 
  --help 在標准輸出上顯示幫助信息。 
  --version 在標准輸出上輸出版本信息並退出。

 ---------------------------------------------------------------------

2.ls命令實現過程用到的函數

函數原型:

1)int stat(const char *path, struct stat *buf);

  stat函數 將path(文件)的屬性信息保存在 buf結構體中

2)struct passwd *getpwuid(uid_t uid);

  getpwuid函數是通過用戶的uid查找用戶的passwd數據,其中包括username

3)struct group *getgrgid(gid_t gid);

  getgrgid函數通過用戶組gid指定的組識別碼逐一搜索組文件,找到時便將該組的數據以group結構返回。

4)struct tm *localtime(const time_t *timep);

   localtime函數把從1970-1-1零點零分到當前時間系統所偏移的秒數時間轉換為日歷時間 。並且此函數獲得的tm結構體的時間,是已經進行過時區轉化為本地時間。

5)  DIR *opendir(const char *name);

  opendir()函數的作用是:打開目錄句柄,返回一個文件描述符。

6)  struct dirent *readdir(DIR *dirp);

  readdir()函數讀取一個目錄文件描述符的信息,將信息返回到dirent結構體中。

 

struct stat 內容:

/* The stat structure.  */
struct stat {
    unsigned long   st_dev;        /* Device.  */
    unsigned long   st_ino;        /* File serial number.  */
    unsigned int    st_mode;       /* File mode.  */
    unsigned int    st_nlink;      /* Link count.  */
    unsigned int    st_uid;        /* User ID of the file's owner.  */
    unsigned int    st_gid;        /* Group ID of the file's group. */
    unsigned long   st_rdev;       /* Device number, if device.  */
    unsigned long   __pad1;
    long            st_size;       /* Size of file, in bytes.  */
    int             st_blksize;    /* Optimal block size for I/O.  */
    int             __pad2;
    long            st_blocks;     /* Number 512-byte blocks allocated. */
    int             st_atime;      /* Time of last access.  */
    unsigned int    st_atime_nsec;
    int             st_mtime;      /* Time of last modification.  */
    unsigned int    st_mtime_nsec;
    int             st_ctime;      /* Time of last status change.  */
    unsigned int    st_ctime_nsec;
    unsigned int    __unused4;
    unsigned int    __unused5;
};

struct stat中的st_mode值各個位代表的意思:

       The following flags are defined for the st_mode field:
      /*  是什么類型的文件  */
           S_IFMT     0170000   bit mask for the file type bit fields
           S_IFSOCK   0140000   socket
           S_IFLNK    0120000   symbolic link
           S_IFREG    0100000   regular file
           S_IFBLK    0060000   block device
           S_IFDIR    0040000   directory
           S_IFCHR    0020000   character device
           S_IFIFO    0010000   FIFO
           S_ISUID    0004000   set UID bit
           S_ISGID    0002000   set-group-ID bit (see below)
           S_ISVTX    0001000   sticky bit (see below)
      /* 是否有可讀寫權限 */ S_IRWXU
00700 mask for file owner permissions S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 mask for group permissions S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 mask for permissions for others (not in group) S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permission S_IXOTH 00001 others have execute permission

struct passwd 內容:

/* The passwd structure.  */
struct passwd
{
  char *pw_name;          /* Username.  */
  char *pw_passwd;        /* Password.  */
  __uid_t pw_uid;         /* User ID.  */
  __gid_t pw_gid;         /* Group ID.  */
  char *pw_gecos;         /* Real name.  */
  char *pw_dir;           /* Home directory.  */
  char *pw_shell;         /* Shell program.  */
};

struct group 內容:

/* The group structure.     */
struct group
  {
    char *gr_name;         /* Group name.    */
    char *gr_passwd;       /* Password.    */
    __gid_t gr_gid;        /* Group ID.    */
    char **gr_mem;         /* Member list.    */
  };

struct tm 內容:

/* Used by other time functions.  */
struct tm
{
  int tm_sec;            /* Seconds.    [0-60] (1 leap second) */
  int tm_min;            /* Minutes.    [0-59] */
  int tm_hour;            /* Hours.    [0-23] */
  int tm_mday;            /* Day.        [1-31] */
  int tm_mon;            /* Month.    [0-11] */
  int tm_year;            /* Year    - 1900.  */
  int tm_wday;            /* Day of week.    [0-6] */
  int tm_yday;            /* Days in year.[0-365]    */
  int tm_isdst;            /* DST.        [-1/0/1]*/

#ifdef    __USE_BSD
  long int tm_gmtoff;        /* Seconds east of UTC.  */
  __const char *tm_zone;    /* Timezone abbreviation.  */
#else
  long int __tm_gmtoff;        /* Seconds east of UTC.  */
  __const char *__tm_zone;    /* Timezone abbreviation.  */
#endif
};

struct dirent內容:

struct dirent
  {
#ifndef __USE_FILE_OFFSET64
    __ino_t d_ino;
    __off_t d_off;
#else
    __ino64_t d_ino;
    __off64_t d_off;
#endif
    unsigned short int d_reclen;
    unsigned char d_type;
    char d_name[256];        /* We must not include limits.h! */
  };

 

 ---------------------------------------------------------------------

3.ls命令的實現

1)首先獲得文件的屬性

const char *path由main函數傳入:

int main(int argc, char **argv)

獲取文件argv[1]的屬性信息,並保存在st結構體中:

if(stat(argv[1], &st) < 0)
    {
        perror("stat");
        return -1;
    }

2)判斷是否是目錄

    if((st.st_mode & S_IFMT) == S_IFDIR)
        display_dir(argv[1]);
    else
        display_file(argv[1], argv[1]);

如果是文件則直接獲取文件信息即可,如果是目錄則要進入到目錄中進行遍歷,我們封裝兩個函數display_file()display_dir()來分別實現

3)目錄與文件的實現

【display_file()】

a.由屬性信息獲得文件的類型 

用stat結構體中的st_mode與掩碼S_IFMT相與,得到文件類型:

switch(st.st_mode & S_IFMT)    
    {
    case S_IFREG:  printf("-");    break;
    case S_IFDIR:  printf("d");    break;
    case S_IFLNK:  printf("l");    break;
    case S_IFBLK:  printf("b");    break;
    case S_IFCHR:  printf("c");    break;
    case S_IFIFO:  printf("p");    break;
    case S_IFSOCK: printf("s");    break;
    }

 b.由屬性信息獲得文件的可讀寫權限

    for(i = 8; i >= 0; i--)
    {    
        if(st.st_mode & (1 << i))
        {
            switch(i%3)
            {
            case 2: printf("r"); break;
            case 1: printf("w"); break;
            case 0: printf("x"); break;
            }
        }
        else
            printf("-");
    }

c.由屬性信息獲得文件的owner和所在的group信息

pw = getpwuid(st.st_uid);
gr = getgrgid(st.st_gid);

d.最后文件所以信息可以打印

printf("%2d %s %s %4ld", st.st_nlink, pw->pw_name, gr->gr_name, st.st_size);

tm = localtime(&st.st_ctime);
printf(" %04d-%02d-%02d %02d:%02d",tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);

printf(" %s\n", filename);

 

【display_dir()】

獲取目錄文件描述符,並且讀取目錄信息,判斷目錄不為空則繼續讀取。如果讀取到的是目錄,則遞歸調用,否則直接調用display_file()即可。

    dir = opendir(dirname);
    while((dirent = readdir(dir)) != NULL)
    {
        strcpy(buf, dirname);
        strcat(buf, "/");
        strcat(buf, dirent->d_name);
        if(stat(buf, &st))
        {
            perror("stat");
            return -1;
        }

        if(dirent->d_name[0] != '.')
            display_file(buf, dirent->d_name);
    }

 

 ---------------------------------------------------------------------

4.結果顯示

查看文件(display_file)結果:

linux@ubuntu:~/test$ ./a.out stat.c 
-rw-r--r-- 1 linux linux 15316 2012-06-19 14:05 stat.c

查看文件夾(display_dir)結果:

linux@ubuntu:~/test$ ./a.out .
-rw-r--r-- 1 linux linux 1508 2012-06-19 14:40 ls.c
-rw-r--r-- 1 linux linux 1635 2012-06-19 14:12 ls-bak.c
-rwxrw-rw- 1 linux linux 1777 2012-06-19 15:02 ls_t.c
-rw-r--r-- 1 linux linux 15316 2012-06-19 14:05 stat.c
-rwxr-xr-x 1 linux linux 7632 2012-06-19 15:14 a.out

 

附:ls 命令實現的完整代碼

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <time.h>

int display_file(char *path, char *filename)
{
    struct stat st;
    int i;
    struct passwd *pw;
    struct group *gr;
    struct tm *tm;
    stat(path, &st);

    switch(st.st_mode & S_IFMT)    
    {
    case S_IFREG:  printf("-");    break;
    case S_IFDIR:  printf("d");    break;
    case S_IFLNK:  printf("l");    break;
    case S_IFBLK:  printf("b");    break;
    case S_IFCHR:  printf("c");    break;
    case S_IFIFO:  printf("p");    break;
    case S_IFSOCK: printf("s");    break;
    }

    for(i = 8; i >= 0; i--)
    {    
        if(st.st_mode & (1 << i))
        {
            switch(i%3)
            {
            case 2: printf("r"); break;
            case 1: printf("w"); break;
            case 0: printf("x"); break;
            }
        }
        else
            printf("-");
    }

    pw = getpwuid(st.st_uid);
    gr = getgrgid(st.st_gid);

    printf("%2d %s %s %4ld", st.st_nlink, pw->pw_name, gr->gr_name, st.st_size);

    tm = localtime(&st.st_ctime);
    printf(" %04d-%02d-%02d %02d:%02d",tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);

    printf(" %s\n", filename);

    return 0;
}

int display_dir(char *dirname)
{
    DIR *dir;
    struct dirent *dirent;
    struct stat st;
    char buf[1024];

    dir = opendir(dirname);
    while((dirent = readdir(dir)) != NULL)
    {
        strcpy(buf, dirname);
        strcat(buf, "/");
        strcat(buf, dirent->d_name);
        if(stat(buf, &st))
        {
            perror("stat");
            return -1;
        }

        if(dirent->d_name[0] != '.')
            display_file(buf, dirent->d_name);
    }
}

int main(int argc, char **argv)
{
    struct stat st;
    char buf[1024];

    if(stat(argv[1], &st) < 0)
    {
        perror("stat");
        return -1;
    }

    if((st.st_mode & S_IFMT) == S_IFDIR)
        display_dir(argv[1]);
    else
        display_file(argv[1], argv[1]);

    return 0;
}

 

關於如何顯示文件顏色的相關介紹可以參看:http://www.embedu.org/Column/Column341.htm

效果圖如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM