• linux下使用c语言模拟ls [-l] [路径名] 命令


    同样是一个作业,这比前一个linux下使用c语言模拟tail [-n] 命令要难一些了。
    这里写图片描述
    但是既然是作业,再麻烦也还是要做的,网上搜到的都是200多行甚至300多行的代码,还没有详细说明,既不想直接copy,也不想去看懂300来行几乎没注释的代码,所以就自己来了。
    不借鉴别人是不可能的,于是我发现了一篇文章linux下用c实现ls命令 ,这是我找到的最简洁的一篇文章了,代码可以直接copy过来,如下:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <dirent.h>
    #include <string.h>
    int main(int argc,char* argv[])
    {
         DIR* dir = opendir(".");
         struct dirent* ent=NULL;
         while((ent = readdir(dir)))
         {
             if((ent->d_type == 4||ent->d_type == 8)&&ent->d_name[0]!='.')
             printf("%s  ",ent->d_name);
         }
         closedir(dir);
         puts("");
         return 0;
    }

    但是显然没有达到我所要的要求,我还需要模拟ls -l 以及自定义目录呀,这篇博客里写的只能显示当前目录下所有文件或者文件夹等的名称,而且输出的排版也有点凌乱。
    看完代码后,当即就发现他是使用一个定义在头文件中的结构体来实现的,那么这个结构体会不会也包含别的信息呢,比如包括了权限信息、组id、最近操作时间等等的。
    我向来是不惮以最好的想法来揣测编写头文件的大佬的,然而我还不料,也不信竟让我失望到如此地步这里写图片描述
    结构体 dirent 的结构如下,从百度百科copy来的:

    struct dirent
    {
    long d_ino; /* inode number 索引节点号 */
    off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
    unsigned short d_reclen; /* length of this d_name 文件名长 */
    unsigned char d_type; /* the type of d_name 文件类型 */
    char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长256字符 */
    }

    这下傻眼了,感情ls -l和这个没搭边。然后我再去看了上面博主的文章,突然在下面发现了原来这位仁兄还写了另一篇:linux 下用 c 实现 ls -l 命令
    不要急着去看,除了有目录固定,格式固定等的局限性外,还有错误。
    我的代码实质上就是将他的两篇博文的功能合并了,然后允许自定义目录,也改掉了他的bug。
    先说下这位博主的错误:
    1、其在通过文件名获取文件细节信息时所用语句为stat( filename, &info ),但是这个函数是判断不出一个文件是不是软链接的,而在ls -l中,如果是软链接,显示中会在软链接的名称后加上->所指向的地址,觉得抽象的去试一下就知道了。因而需要改成lstat( filename, &info ),就是将stat改成lstat。
    2、上述错误可以说是这位博主没有考虑到的地方,因为其并未判断文件是否为软链接,因此在mode_to_letters() 函数中,应该加上if( S_ISLNK(mode) ) str[0] = 'l';

    而该文章中我一处不明白的就在:printf("%.12s ", 4 + ctime(&info_p->st_mtime));,这条语句写了4+ 不知道是为什么,但是加上和不加的时候样式有区别,如果有大佬知道望告知。

    下面就放我的完整代码吧,linux虚拟机里没装中文输入法,注释用英文写了:

    #include<stdio.h>
    #include<unistd.h>
    #include<dirent.h>
    #include<sys/stat.h>
    #include<string.h>
    #include<pwd.h>
    #include<grp.h>
    
    
    
    int main(int argc,char **argv)
    {
        char c;
        char *path = ".";
        int isL = 0;    //if have -l,set isL=1,or isL=0
        while((c=getopt(argc,argv,"l"))!=-1)
        {
            isL = 1;
    
        }
        //printf("%d:%d",argc,optind);
        if(argc > optind)
        {
            path = argv[optind];
        }
        //printf("%s",path);
    
        struct dirent* ent = NULL;
        DIR* dir = opendir(path);
        int newLine = 0;
        while((ent = readdir(dir)))
        {
            if(isL == 0)
            {
                if((ent->d_type == 4 || ent->d_type == 8) && ent->d_name[0]!='.')
                {
                    printf("%-24s",ent->d_name);
                    newLine++;
                    if(newLine % 3 == 0) printf("
    ");
                }
            }
            else
            {
                struct stat info;
                //get directory detail info             
                char temp[80];
                strcpy(temp,path);
                strcat(temp,"/");
                strcat(temp,ent->d_name);
                if(lstat(temp,&info) == -1)
                {
                    printf("Cannot open the directory:%s",temp);
                    break;
                }
                else
                {
                    if(ent->d_name[0]!='.')
                    {
                        char *uid_to_name(),*ctime(),*gid_to_name(),*filemode();
                        void mode_to_letters();
                        char modestr[11];
    
                        //transfer mode to letters
                        mode_to_letters(info.st_mode,modestr);
    
                        printf("%s",modestr);
                        printf("%4d",(int)info.st_nlink);
                        printf("%8s",uid_to_name(info.st_uid));
                        printf("%8s",gid_to_name(info.st_gid)); 
                        printf("%10ld  ",(long)info.st_size);           
                        printf("%.12s  ",4+ctime(&info.st_mtime));
    
                        printf("%s",ent->d_name);
    
                        static char linkPath[1024];
    
                        readlink(temp,linkPath,1024);
                        if(S_ISLNK(info.st_mode))
                        {
                            printf("->%s",linkPath);
                        }                   
    
    
                        printf("
    ");
                    }
                }
            }
    
        }
        closedir(dir);
        puts("");
    }
    
    void mode_to_letters(int mode,char str[])
    {
        strcpy(str,"----------");
        if(S_ISDIR(mode)) str[0] = 'd';     //directory
        if(S_ISCHR(mode)) str[0] = 'c';     //characteristic
        if(S_ISBLK(mode)) str[0] = 'b';     //block
        if(S_ISLNK(mode)) str[0] = 'l';     //link
    
        if(mode & S_IRUSR) str[1]= 'r';
        if(mode & S_IWUSR) str[2]= 'w';
        if(mode & S_IXUSR) str[3]= 'x';
    
        if(mode & S_IRGRP) str[4]= 'r';
        if(mode & S_IWGRP) str[5]= 'w';
        if(mode & S_IXGRP) str[6]= 'x';
    
        if(mode & S_IROTH) str[7]= 'r';
        if(mode & S_IWOTH) str[8]= 'w';
        if(mode & S_IXOTH) str[9]= 'x';
    }
    
    char *uid_to_name(uid_t uid)
    {
        struct passwd *getpwuid(),*pw_ptr;
        static char numstr[10];
        if((pw_ptr = getpwuid(uid)) == NULL)
        {
            sprintf(numstr,"%d",uid);
            return numstr;
        }
        return pw_ptr->pw_name;
    }
    
    char *gid_to_name(gid_t gid)
    {
        struct group *getgrgid(),*grp_ptr;
        static char numstr[10];
        if((grp_ptr = getgrgid(gid)) == NULL)
        {
            sprintf(numstr,"%d",gid);
            return numstr;
        }
        return grp_ptr->gr_name;
    }
    

    这里写图片描述

  • 相关阅读:
    centos 查看版本(转)
    防火墙内设置FileZilla Server注意事项
    mycat读写分离与主从切换
    用mycat做读写分离:基于 MySQL主从复制
    mysql处理海量数据时的一些优化查询速度方法
    CentOS下LVS DR模式负载均衡配置详解
    Linux清除arp缓存
    扫描局域网内所有主机和MAC地址的Shell脚本
    Windows+Python 3.6环境下安装PyQt4
    Python 爬虫-豆瓣读书
  • 原文地址:https://www.cnblogs.com/yinyoupoet/p/13287555.html
Copyright © 2020-2023  润新知