zoukankan      html  css  js  c++  java
  • [Linux环境编程] Linux系统命令“ls -l”的实现

    Linux系统命令“ls -l”的实现

     

    一、基本概念

    1、“ls -l”的意义

      以长格式显示目录下的内容列表。输出的信息从左到右依次包括文件名,文件类型、权限模式、硬连接数、所有者、组、文件大小和文件的最后修改时间等。

      例:-rw-rw-r--   1  using using  3102  7月 22 17:06  test.c 

        drwxrwxr-x  2  using using  4096  7月 22 18:39  testdir 

        lrwxrwxrwx  1  using using      17   7月 22 18:43  shared -> /media/sf_shared/

      其中深蓝色为目录文件,天蓝色为软连接文件(具体颜色和vimrc配置有关)。

      第一字段:首字母代表的是文件类型 ,其中"-"为普通文件、"d"为目录文件、"c"为字符设备文件、"b"为块设备文件、"p"为管道文件、"l"为链接文件、"s"为socket文件。“rwx”分别代表拥有读、写和执行权限,“-”代表无对应权限。三个“rwx”依次代表文件所有者、文件所有者所在用户组、其它用户对文件拥有的权限

      第二字段:文件硬连接数量

      第三字段:文件拥有者

      第四字段:文件拥有者所在组

      第五字段:文件大小(以字节为单位)

      第六字段:文件最后更改时间

      第七字段:文件名(若为链接文件则追加显示其链接的原文件的路径)

      

    二、重要函数与结构体

    1、目录操作函数

     1        #include <sys/types.h>
     2        #include <dirent.h>
     3 
     4        DIR *opendir(const char *name);
     5        DIR *fdopendir(int fd);
     6 
     7 
     8        #include <dirent.h>
     9 
    10        struct dirent *readdir(DIR *dirp);
    11 
    12            struct dirent {
    13                ino_t          d_ino;       /* inode number */
    14                off_t          d_off;       /* offset to the next dirent */
    15                unsigned short d_reclen;    /* length of this record */
    16                unsigned char  d_type;      /* type of file; not supported by all file system types */
    17                char           d_name[256]; /* filename */
    18            };

    2、 获取文件信息

      这里必须使用int lstat(const char *path, struct stat *buf);函数,否则在处理链接文件时会将其链接的原文件作为处理对象,而不是它本身。

     1        #include <sys/types.h>
     2        #include <sys/stat.h>
     3        #include <unistd.h>
     4 
     5        int stat(const char *path, struct stat *buf);
     6        int fstat(int fd, struct stat *buf);
     7        int lstat(const char *path, struct stat *buf);
     8 
     9            struct stat {
    10                dev_t     st_dev;     /* ID of device containing file */
    11                ino_t     st_ino;     /* inode number */
    12                mode_t    st_mode;    /* protection */
    13                nlink_t   st_nlink;   /* number of hard links */
    14                uid_t     st_uid;     /* user ID of owner */
    15                gid_t     st_gid;     /* group ID of owner */
    16                dev_t     st_rdev;    /* device ID (if special file) */
    17                off_t     st_size;    /* total size, in bytes */
    18                blksize_t st_blksize; /* blocksize for file system I/O */
    19                blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    20                time_t    st_atime;   /* time of last access */
    21                time_t    st_mtime;   /* time of last modification */
    22                time_t    st_ctime;   /* time of last status change */
    23            };

    3、 文件类型及权限的判断

     1        The following POSIX macros are defined to check the file type using the st_mode field:
     2 
     3            S_ISREG(m)  is it a regular file?
     4            S_ISDIR(m)  directory?
     5            S_ISCHR(m)  character device?
     6            S_ISBLK(m)  block device?
     7            S_ISFIFO(m) FIFO (named pipe)?
     8            S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)
     9            S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
    10 
    11 
    12        The following flags are defined for the st_mode field:
    13 
    14            S_IFMT     0170000   bit mask for the file type bit fields
    15            S_IFSOCK   0140000   socket
    16            S_IFLNK    0120000   symbolic link
    17            S_IFREG    0100000   regular file
    18            S_IFBLK    0060000   block device
    19            S_IFDIR    0040000   directory
    20            S_IFCHR    0020000   character device
    21            S_IFIFO    0010000   FIFO
    22            S_ISUID    0004000   set UID bit
    23            S_ISGID    0002000   set-group-ID bit (see below)
    24            S_ISVTX    0001000   sticky bit (see below)
    25            S_IRWXU    00700     mask for file owner permissions
    26            S_IRUSR    00400     owner has read permission
    27            S_IWUSR    00200     owner has write permission
    28            S_IXUSR    00100     owner has execute permission
    29            S_IRWXG    00070     mask for group permissions
    30            S_IRGRP    00040     group has read permission
    31            S_IWGRP    00020     group has write permission
    32            S_IXGRP    00010     group has execute permission
    33            S_IRWXO    00007     mask for permissions for others (not in group)
    34            S_IROTH    00004     others have read permission
    35            S_IWOTH    00002     others have write permission
    36            S_IXOTH    00001     others have execute permission

    4、文件用户ID与用户所在组ID的转换

     1        #include <sys/types.h>
     2        #include <pwd.h>
     3 
     4        struct passwd *getpwnam(const char *name);
     5        struct passwd *getpwuid(uid_t uid);
     6        int getpwnam_r(const char *name, struct passwd *pwd,char *buf, size_t buflen, struct passwd **result);
     7        int getpwuid_r(uid_t uid, struct passwd *pwd,char *buf, size_t buflen, struct passwd **result);
     8 
     9 
    10         The passwd structure is defined in <pwd.h> as follows:
    11 
    12            struct passwd {
    13                char   *pw_name;       /* username */
    14                char   *pw_passwd;     /* user password */
    15                uid_t   pw_uid;        /* user ID */
    16                gid_t   pw_gid;        /* group ID */
    17                char   *pw_gecos;      /* user information */
    18                char   *pw_dir;        /* home directory */
    19                char   *pw_shell;      /* shell program */
    20            };
     1        #include <sys/types.h>
     2        #include <grp.h>
     3 
     4        struct group *getgrnam(const char *name);
     5        struct group *getgrgid(gid_t gid);
     6        int getgrnam_r(const char *name, struct group *grp,char *buf, size_t buflen, struct group **result);
     7        int getgrgid_r(gid_t gid, struct group *grp,char *buf, size_t buflen, struct group **result);
     8 
     9 
    10        The group structure is defined in <grp.h> as follows:
    11 
    12            struct group {
    13                char   *gr_name;       /* group name */
    14                char   *gr_passwd;     /* group password */
    15                gid_t   gr_gid;        /* group ID */
    16                char  **gr_mem;        /* group members */
    17            };

    5、文件最后修改时间

      文件最后修改时间可以通过tm结构体接收localtime函数返回值来获取。

     1        #include <time.h>
     2 
     3        struct tm *localtime(const time_t *timep);
     4        struct tm *localtime_r(const time_t *timep, struct tm *result);
     5 
     6 
     7        Broken-down time is stored in the structure tm which is defined in <time.h> as follows:
     8 
     9            struct tm {
    10                int tm_sec;         /* seconds */
    11                int tm_min;         /* minutes */
    12                int tm_hour;        /* hours */
    13                int tm_mday;        /* day of the month */
    14                int tm_mon;         /* month */
    15                int tm_year;        /* year */
    16                int tm_wday;        /* day of the week */
    17                int tm_yday;        /* day in the year */
    18                int tm_isdst;       /* daylight saving time */
    19            };

    三、执行结果及对比

     

     

    四、总结

      总的来说,实现“ls -l”功能所涉及的特殊结构体较多,基础知识考察较多,需要构建很多小函数,较为繁杂,但逻辑结构简单,没有什么需要特别留意的地方,总体难度较低。

      本博是在博友“Apollon_krj”的一篇博客“Linux&C编程之Linux系统命令“ls -l”的简单实现”的基础上改进完成。总体沿用了原有思路和框架,做了以下改良:

      1. 可以处理软连接文件(原处理链接文件所链接的原文件);

      2. 当输入“myls -l”指令时默认显示当前目录下文件的详细信息(原报错);

      3. 指令、代码优化。

      但目前暂未实现总用量/total、模糊匹配和彩字显示功能,有兴趣的朋友可以尝试一下。

    五、实现代码

    1、myls.h

     1 #ifndef _MYLS_H_
     2 #define _MYLS_H_
     3 
     4 #include<stdio.h>
     5 #include<stdlib.h>
     6 #include<string.h>
     7 #include<unistd.h>
     8 #include<dirent.h>
     9 #include<sys/stat.h>
    10 #include<sys/types.h>
    11 #include<fcntl.h>
    12 #include<time.h>
    13 #include<pwd.h>
    14 #include<grp.h>
    15 
    16 // 处理错误
    17 void error_printf(const char* );
    18 
    19 // 处理路径下的文件
    20 void list_dir(const char* );
    21 void list_message(const char* , const struct stat*);
    22 
    23 // 所显示的文件信息
    24 void file_type(const struct stat* );
    25 void file_power(const struct stat* );
    26 // printf st_nlink
    27 void file_id(const struct stat* );
    28 // printf st_size
    29 void file_mtime(const struct stat* );
    30 // printf filename
    31 void link_printf(const char* );
    32 
    33 #endif//_MYLS_H_

    2、 myls.c

      1 #include "myls.h"
      2 
      3 // 处理错误
      4 void error_printf(const char* funname)
      5 {
      6     perror(funname);
      7     exit(EXIT_FAILURE);
      8     /* 
      9     * EXIT_SUCCESS和EXIT_FAILURE是两个常量。
     10     * EXIT_SUCCESS=0,EXIT_FAILURE=1。
     11     * 0表示程序寿终正寝,1表示死于非命。
     12     */
     13 }
     14 
     15 // 读取路径下的文件
     16 void list_dir(const char* pathname)
     17 {
     18     DIR* ret_opendir = opendir(pathname); // 打开目录"pathname"
     19     if(ret_opendir == NULL)
     20         error_printf("opendir");
     21 
     22     int ret_chdir = chdir(pathname); // 改变工作目录至"pathname",便于stat函数的使用
     23     if(ret_chdir == -1)
     24         error_printf("chdir");
     25 
     26     struct dirent* ret_readdir = NULL; // 定义readdir函数返回的结构体变量
     27     while(ret_readdir = readdir(ret_opendir)) // 判断是否读取到目录尾
     28     {
     29         char* filename = ret_readdir->d_name; // 获取文件名
     30         struct stat file_message = {}; // 定义stat函数返回的结构体变量
     31         int ret_stat = lstat(filename, &file_message); // 获取文件信息
     32         if(ret_stat == -1) // stat读取文件错误则输出提示信息
     33             printf("%s error!", filename);
     34         else if(strcmp(filename,".") && strcmp(filename,"..")) // 不输出当前目录与上一级目录
     35             list_message(filename, &file_message);
     36     }
     37 }
     38 
     39 // 打印所读取文件的信息
     40 void list_message(const char* filename, const struct stat* file_message)
     41 {
     42     file_type(file_message); // 判断打印文件类型
     43     file_power(file_message); // 判断并打印文件权限
     44     printf("%d ", file_message->st_nlink); // 打印硬链接数
     45     file_id(file_message); // 转换并打印用户id与组id
     46     printf("%5ld ", file_message->st_size); // 打印文件大小
     47     file_mtime(file_message); // 打印文件最后修改时间
     48     printf("%s ", filename); // 打印文件名
     49     if(S_ISLNK(file_message->st_mode)) // 如果是软链接文件,打印其指向的位置
     50         link_printf(filename);
     51     puts("");
     52 }
     53 
     54 
     55 // 所显示的文件信息
     56 void file_type(const struct stat* file_message) 
     57 {
     58     //mode_t mode = (*get_message).st_mode;
     59     mode_t mode = file_message->st_mode;
     60 
     61     if     (S_ISREG(mode))  printf("-"); // 普通文件
     62     else if(S_ISDIR(mode))  printf("d"); // 目录文件
     63     else if(S_ISCHR(mode))  printf("c"); // 字符设备文件
     64     else if(S_ISBLK(mode))  printf("b"); // 块设备文件
     65     else if(S_ISFIFO(mode)) printf("p"); // 管道文件
     66     else if(S_ISLNK(mode))  printf("l"); // 链接文件
     67     else                    printf("s"); // socket文件
     68 }
     69 
     70 void file_power(const struct stat* file_message)
     71 {
     72     mode_t mode = file_message->st_mode;
     73 
     74     // 判断USR权限
     75     printf("%c", mode&S_IRUSR?'r':'-');
     76     printf("%c", mode&S_IWUSR?'w':'-');
     77     printf("%c", mode&S_IXUSR?'x':'-');
     78 
     79     // 判断GRP权限
     80     printf("%c", mode&S_IRGRP?'r':'-');
     81     printf("%c", mode&S_IWGRP?'w':'-');
     82     printf("%c", mode&S_IXGRP?'x':'-');
     83 
     84     // 判断OTH权限
     85     printf("%c", mode&S_IROTH?'r':'-');
     86     printf("%c", mode&S_IWOTH?'w':'-');
     87     printf("%c ", mode&S_IXOTH?'x':'-');
     88 }
     89 
     90 void file_id(const struct stat* file_message)
     91 {
     92     // 根据用户id获取用户名
     93     struct passwd* pwd;
     94     pwd = getpwuid(file_message->st_uid);
     95     printf("%s ",pwd->pw_name);
     96 
     97     // 根据组id获取组名
     98     struct group* grp;
     99     grp = getgrgid(file_message->st_gid);
    100     printf("%s ",grp->gr_name);
    101 
    102     #if 0
    103     struct passwd  
    104     {  
    105         char * pw_name; /* Username, POSIX.1 */  
    106         char * pw_passwd; /* Password */  
    107         __uid_t pw_uid; /* User ID, POSIX.1 */  
    108         __gid_t pw_gid; /* Group ID, POSIX.1 */  
    109         char * pw_gecos; /* Real Name or Comment field */  
    110         char * pw_dir; /* Home directory, POSIX.1 */  
    111         char * pw_shell; /* Shell Program, POSIX.1 */  
    112     };  
    113 
    114     struct group
    115     {
    116         char *gr_name;  /* Group name */
    117         char *gr_passwd;  /* password */
    118         __gid_t gr_gid;  /* Group ID */
    119         char **gr_mem;  /* Member list */
    120     }
    121     #endif//0
    122 }
    123 
    124 void file_mtime(const struct stat* file_message)
    125 {
    126     struct tm* t = localtime(&file_message->st_mtime);
    127     printf("%2d月 %2d %02d:%02d ", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min);
    128 }
    129 
    130 void link_printf(const char* filename)
    131 {
    132     char buf[1024] = "123";
    133     if(0 == readlink(filename, buf, sizeof(buf)))
    134         error_printf("readlink");
    135     printf("-> %s ",buf);
    136 }

    3、main_myls.c

     1 #include "myls.h"
     2 
     3 
     4 int main(const char argc, const char** argv)
     5 {
     6     char path[1024] = {};
     7 
     8     if(argc == 2 && !(strcmp(argv[1],"-l"))) // 判断命令格式
     9         strcpy(path,"./");
    10     else if(argc != 3)
    11     {
    12         printf("usage:ls -l pathname. 
    ");
    13         exit(EXIT_FAILURE);
    14     }
    15     else
    16         strcpy(path,argv[2]);
    17 
    18     if(!(strcmp(argv[1],"-l")))
    19     {
    20         struct stat file_message = {};
    21         int ret_stat = lstat(path, &file_message);
    22 
    23         if(ret_stat == -1)
    24                error_printf("stat");
    25 
    26         if(S_ISDIR(file_message.st_mode)) // 判断是否为目录
    27             list_dir(path);
    28         else
    29             list_message(path, &file_message);
    30     }
    31     else
    32     {
    33         printf("error in main!
    ");
    34         exit(EXIT_FAILURE);
    35     }                    
    36     return 0;
    37 }
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Qt 自定义model实现文件系统的文件名排序
  • 原文地址:https://www.cnblogs.com/usingnamespace-caoliu/p/9351773.html
Copyright © 2011-2022 走看看