• linux系统编程:自己动手写一个ls命令


    ls用于列举目录内容,要实现这个功能,毫无疑问,需要读取目录,涉及到两个api:

    opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列

    readdir:struct dirent *readdir(DIR *dirp), 把opendir的返回值传过来,   返回值为一个结构体

            struct dirent {
                   ino_t          d_ino;       /* inode number */
                   off_t          d_off;       /* not an offset; see NOTES */
                   unsigned short d_reclen;    /* length of this record */
                   unsigned char  d_type;      /* type of file; not supported
                                                  by all filesystem types */
                   char           d_name[256]; /* filename */
               };

    有了这两个api,就可以实现一个简易的ls功能

     1 /*================================================================
     2 *   Copyright (C) 2018 . All rights reserved.
     3 *   
     4 *   文件名称:myls.c
     5 *   创 建 者:ghostwu(吴华)
     6 *   创建日期:2018年01月09日
     7 *   描    述: ls命令
     8 *
     9 ================================================================*/
    10 
    11 #include <stdio.h>
    12 #include <sys/types.h>
    13 #include <dirent.h>
    14 #include <stdlib.h>
    15 
    16 void do_ls( char [] );
    17 
    18 int main(int argc, char *argv[])
    19 {
    20     if( argc == 1 ) {
    21         do_ls( "." );
    22     }else {
    23         while( --argc ) {
    24             printf( "arg=%s
    ", * ++argv );
    25             do_ls( *argv );
    26         }
    27     }
    28     return 0;
    29 }
    30 
    31 void do_ls( char dir_entry[] ) {
    32     DIR* pDir;
    33     struct dirent* pCurDir;
    34     if( ( pDir = opendir( dir_entry ) ) == NULL ){
    35         perror( "read dir" );
    36         exit( -1 );
    37     }else {
    38         while( ( pCurDir = readdir( pDir ) ) != NULL ) {
    39             printf( "%s
    ", pCurDir->d_name );
    40         }
    41     }
    42 }
    View Code

    这个简易的ls功能,列举出了所有的文件( 包括隐藏的 ), 但是很多的信息不全,如: 权限,用户和组,修改时间,文件大小,链接数目等,stat这个api可以获取文件的这些信息

    stat:获取文件状态信息

    原型:int stat(const char *pathname, struct stat *buf), 第一个参数:文件名, 第二个参数:保存文件状态信息的结构体( man 2 stat 有结构体相关说明 )

    1、获取文件的大小

     1 /*================================================================
     2 *   Copyright (C) 2018 . All rights reserved.
     3 *   
     4 *   文件名称:stat.c
     5 *   创 建 者:ghostwu(吴华)
     6 *   创建日期:2018年01月09日
     7 *   描    述:
     8 *
     9 ================================================================*/
    10 
    11 #include <stdio.h>
    12 #include <sys/stat.h>
    13 
    14 #define FILENAME "/etc/passwd"
    15 
    16 int main(int argc, char *argv[])
    17 {
    18     struct stat filestat;
    19     
    20     if( -1 == stat( FILENAME, &filestat ) ) {
    21         perror( "file stat" );
    22         return -1;
    23     }else {
    24         printf( "the size of %s is %ld
    ",FILENAME,  filestat.st_size );
    25     }
    26 
    27     return 0;
    28 }
    View Code

    2、读取文件st_mode(权限位), 用户id, 组id, 修改时间,链接数目

     1 /*================================================================
     2 *   Copyright (C) 2018 . All rights reserved.
     3 *   
     4 *   文件名称:stat2.c
     5 *   创 建 者:ghostwu(吴华)
     6 *   创建日期:2018年01月09日
     7 *   描    述:
     8 *
     9 ================================================================*/
    10 
    11 #include <stdio.h>
    12 #include <sys/stat.h>
    13 #include <string.h>
    14 #include <time.h>
    15 
    16 void show_info( char *file, struct stat* statinfo );
    17 void show_time( time_t filetime );
    18 char* format_time( char* dsttime, const char* srctime );
    19 
    20 int main(int argc, char *argv[])
    21 {
    22     struct stat fileinfo;
    23     if( argc > 1 ) {
    24         /*调试信息
    25         printf( "%s
    ", argv[1] );
    26         int res = stat( argv[1], &fileinfo );
    27         printf( "%d
    ", res );
    28         */
    29         if( stat( argv[1], &fileinfo ) != -1 ) {
    30             show_info( argv[1], &fileinfo );
    31         }
    32     }else {
    33         perror( "get args from terminal" );
    34     }
    35     
    36     return 0;
    37 }
    38 
    39 void show_info( char* file, struct stat* statinfo ){
    40     printf( "%s文件信息如下:
    ", file );
    41     printf( "st_mode = %d
    ", statinfo->st_mode );
    42     printf( "links = %ld
    ", statinfo->st_nlink );
    43     printf( "uid = %d
    ", statinfo->st_uid );
    44     printf( "gid = %d
    ", statinfo->st_gid );
    45     printf( "file size = %ld
    ", statinfo->st_size );
    46     show_time( statinfo->st_mtime );
    47 }
    48 
    49 void show_time( time_t filetime ) {
    50     struct tm* ptm;
    51     ptm = localtime( &filetime );
    52 
    53     int month = ptm->tm_mon + 1;
    54     int day = ptm->tm_mday;
    55     int hour = ptm->tm_hour;
    56     int min = ptm->tm_min;
    57 
    58     char srchour[3] = "0";
    59     char srcmin[3] = "0";
    60     char dsthour[3] = "0";
    61     char dstmin[3] = "0";
    62     sprintf( srchour, "%d", hour );
    63     sprintf( srcmin, "%d", min );
    64     format_time( dsthour, srchour );
    65     format_time( dstmin, srcmin );
    66 
    67     printf( "文件最后修改时间: %d月	%d	%s:%s
    ", month, day, dsthour, dstmin );
    68 }
    69 
    70 char* format_time( char* dsttime, const char* srctime ) {
    71     if( strlen( srctime ) < 2 ) {
    72         return strcat( dsttime, srctime );
    73     }
    74     return strcpy( dsttime, srctime );
    75 }
    View Code

    3、权限st_mode转字符权限位( 如: -rwxrwxrwx ), 用户id和组id转用户名和组名称,判断文件类型

      1 /*================================================================
      2 *   Copyright (C) 2018 . All rights reserved.
      3 *   
      4 *   文件名称:stat3.c
      5 *   创 建 者:ghostwu(吴华)
      6 *   创建日期:2018年01月09日
      7 *   描    述:文件类型与权限位
      8 *
      9 ================================================================*/
     10 
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <sys/stat.h>
     14 #include <string.h>
     15 #include <sys/types.h>
     16 #include <pwd.h>
     17 #include <grp.h>
     18 
     19 void do_ls( char* filename );
     20 void show_filetype( char* filename, int filemode );
     21 void show_filetype2( char* filename, int filemode );
     22 void mode_to_letters( int filemode, char str[] );
     23 //用户id转名称
     24 char* uid_to_name( uid_t uid );
     25 //组id转名称
     26 char* gid_to_name( gid_t gid );
     27 
     28 int main(int argc, char *argv[])
     29 {
     30     if( argc < 2 ) {
     31         printf( "usage:%s file
    ", argv[0] );
     32         return -1;
     33     }else {
     34         do_ls( argv[1] );
     35     }
     36     return 0;
     37 }
     38 
     39 char* uid_to_name( uid_t uid ){
     40     return getpwuid( uid )->pw_name;
     41 }
     42 
     43 char* gid_to_name( gid_t gid ){
     44     return getgrgid( gid )->gr_name;
     45 }
     46 
     47 void do_ls( char* filename ) {
     48     struct stat fileinfo;
     49     if( stat( filename, &fileinfo ) == -1 ) {
     50         printf( "%s open failure
    ", filename );
     51         exit( -1 );
     52     }
     53     //printf( "st_mode = %d
    ", fileinfo.st_mode );    
     54     show_filetype( filename, fileinfo.st_mode );
     55     show_filetype2( filename, fileinfo.st_mode );
     56     char file_permission[10];
     57     mode_to_letters( fileinfo.st_mode, file_permission );
     58     printf( "%s
    ", file_permission  );
     59     printf( "用户:%s
    ", uid_to_name( fileinfo.st_uid ) );
     60     printf( "组:%s
    ", gid_to_name( fileinfo.st_gid ) );
     61 }
     62 
     63 //掩码判断文件类型
     64 void show_filetype( char* filename, int filemode ){
     65     //用st_mode的值跟0170000这个掩码相位与的结果 判断文件类型
     66     if ( ( filemode & 0170000 ) == 0100000 ){
     67         printf( "%s是普通文件
    ", filename );
     68     }else if( ( filemode & 0170000 ) == 0040000 ){ 
     69         printf( "%s是目录
    ", filename );
     70     }else if ( ( filemode & S_IFMT ) == S_IFLNK ){
     71         printf( "%s是符号链接
    ", filename );
     72     }
     73 }
     74 
     75 //用宏判断文件类型
     76 void show_filetype2( char* filename, int filemode ){
     77     if( S_ISREG( filemode ) ) {
     78         printf( "%s是普通文件
    ", filename );
     79     }else if( S_ISDIR( filemode ) ) {
     80         printf( "%s是目录
    ", filename );
     81     }else if( S_ISLNK( filemode ) ){
     82         printf( "%s是符号链接
    ", filename );
     83     }
     84 }
     85 
     86 //数字解码成字母权限位
     87 void mode_to_letters( int filemode, char str[] ) {
     88     strcpy( str, "----------" );
     89     if( S_ISREG( filemode ) ) str[0] = '-';
     90     if( S_ISDIR( filemode ) ) str[0] = 'd';
     91     if( S_ISLNK( filemode ) ) str[0] = 'l';
     92 
     93     //用户权限位
     94     if( filemode & S_IRUSR ) str[1] = 'r';
     95     if( filemode & S_IWUSR ) str[2] = 'w';
     96     if( filemode & S_IXUSR ) str[3] = 'x';
     97 
     98     //组权限位
     99     if( filemode & S_IRGRP ) str[4] = 'r';
    100     if( filemode & S_IWGRP ) str[5] = 'w';
    101     if( filemode & S_IXGRP ) str[6] = 'x';
    102 
    103     //其他组权限位
    104     if( filemode & S_IROTH ) str[7] = 'r';
    105     if( filemode & S_IWOTH ) str[8] = 'w';
    106     if( filemode & S_IXOTH ) str[9] = 'x';
    107 }
    View Code

    综合上面3个小实例,可以得到格式化比较好的ls命令版本:

      1 /*================================================================
      2 *   Copyright (C) 2018 . All rights reserved.
      3 *   
      4 *   文件名称:myls2.c
      5 *   创 建 者:ghostwu(吴华)
      6 *   创建日期:2018年01月09日
      7 *   描    述:ls命令( version 1.2 )
      8 *
      9 ================================================================*/
     10 
     11 #include <stdio.h>
     12 #include <sys/types.h>
     13 #include <dirent.h>
     14 #include <stdlib.h>
     15 #include <sys/types.h>
     16 #include <sys/stat.h>
     17 #include <unistd.h>
     18 #include <string.h>
     19 #include <sys/types.h>
     20 #include <pwd.h>
     21 #include <grp.h>
     22 #include <time.h>
     23 
     24 void do_ls( char [] );
     25 void do_stat( char* filename );
     26 void show_list( char* filename, struct stat* statinfo );
     27 void mode_to_letters( mode_t filemode, char str[] );
     28 void show_time( time_t filetime );
     29 char* format_time( char* dsttime, const char* srctime );
     30 
     31 //用户id转名称
     32 char* uid_to_name( uid_t uid );
     33 //组id转名称
     34 char* gid_to_name( gid_t gid );
     35 
     36 int main(int argc, char *argv[])
     37 {
     38     if( argc == 1 ) {
     39         do_ls( "." );
     40     }else {
     41         while( --argc ) {
     42             printf( "arg=%s
    ", * ++argv );
     43             do_ls( *argv );
     44         }
     45     }
     46     return 0;
     47 }
     48 
     49 void do_ls( char dir_entry[] ) {
     50     DIR* pDir;
     51     struct dirent* pCurDir;
     52     if( ( pDir = opendir( dir_entry ) ) == NULL ){
     53         perror( "read dir" );
     54         exit( -1 );
     55     }else {
     56         while( ( pCurDir = readdir( pDir ) ) != NULL ) {
     57             do_stat( pCurDir->d_name );
     58         }
     59         closedir( pDir );
     60     }
     61 }
     62 
     63 //得到文件信息
     64 void do_stat( char* filename ){
     65     struct stat statinfo;
     66     if ( stat( filename, &statinfo ) == -1 ) {
     67         printf( "打开%s失败
    ", filename );
     68         exit( -1 );
     69     }else {
     70         show_list( filename, &statinfo );
     71     }
     72 }
     73 
     74 //显示文件列表
     75 void show_list( char* filename, struct stat* statinfo ) {
     76     mode_t st_mode = statinfo->st_mode;
     77 
     78     char str[10];
     79     mode_to_letters( st_mode, str );
     80     printf( "%s	", str );
     81 
     82     printf( "%ld	", statinfo->st_nlink ); //符号链接
     83     printf( "%s		", uid_to_name( statinfo->st_uid ) ); //用户名
     84     printf( "%s	", gid_to_name( statinfo->st_gid ) ); //组名
     85     printf( "%10ld", statinfo->st_size ); //文件大小
     86     show_time( statinfo->st_mtime ); //最后一次修改时间
     87     printf( "	%s", filename );
     88 
     89     printf( "
    " );
     90 }
     91 
     92 char* uid_to_name( uid_t uid ){
     93     return getpwuid( uid )->pw_name;
     94 }
     95 
     96 char* gid_to_name( gid_t gid ){
     97     return getgrgid( gid )->gr_name;
     98 }
     99 
    100 void mode_to_letters( mode_t filemode, char str[] ) {
    101 
    102     strcpy( str, "----------" );
    103     if( S_ISREG( filemode ) ) str[0] = '-';
    104     if( S_ISDIR( filemode ) ) str[0] = 'd';
    105     if( S_ISLNK( filemode ) ) str[0] = 'l';
    106 
    107     //用户权限位
    108     if( filemode & S_IRUSR ) str[1] = 'r';
    109     if( filemode & S_IWUSR ) str[2] = 'w';
    110     if( filemode & S_IXUSR ) str[3] = 'x';
    111 
    112     //组权限位
    113     if( filemode & S_IRGRP ) str[4] = 'r';
    114     if( filemode & S_IWGRP ) str[5] = 'w';
    115     if( filemode & S_IXGRP ) str[6] = 'x';
    116 
    117     //其他组权限位
    118     if( filemode & S_IROTH ) str[7] = 'r';
    119     if( filemode & S_IWOTH ) str[8] = 'w';
    120     if( filemode & S_IXOTH ) str[9] = 'x';
    121 }
    122 
    123 void show_time( time_t filetime ) {
    124     struct tm* ptm;
    125     ptm = localtime( &filetime );
    126 
    127     int month = ptm->tm_mon + 1;
    128     int day = ptm->tm_mday;
    129     int hour = ptm->tm_hour;
    130     int min = ptm->tm_min;
    131 
    132     char srchour[3] = "0";
    133     char srcmin[3] = "0";
    134     char dsthour[3] = "0";
    135     char dstmin[3] = "0";
    136     sprintf( srchour, "%d", hour );
    137     sprintf( srcmin, "%d", min );
    138     format_time( dsthour, srchour );
    139     format_time( dstmin, srcmin );
    140 
    141     printf( "%4d月%4d%4s:%2s", month, day, dsthour, dstmin );
    142 }
    143 
    144 char* format_time( char* dsttime, const char* srctime ) {
    145     if( strlen( srctime ) < 2 ) {
    146         return strcat( dsttime, srctime );
    147     }
    148     return strcpy( dsttime, srctime );
    149 }
    View Code

    总结:

    1)opendir和readdir的用法

    2)结构体struct dirent的应用

    3)stat的用法

  • 相关阅读:
    IOS无线客户端自动化测试
    junit 测试报错 java.lang.Exception: No runnable methods
    mysql varchar(128)可以存多少汉字
    求两个数的百分比
    日期转换
    两个 integer 值判断是否相等
    整洁代码之道——重构
    Eclipse里项目名有红叉,但是底下的每一个文件都没有红叉
    #dubbo# XML文件报错dubbo:XX解决方法
    String处理入门
  • 原文地址:https://www.cnblogs.com/ghostwu/p/8253623.html
Copyright © 2020-2023  润新知