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("\n");
            }
        }
        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("\n");
                }
            }
        }

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

这里写图片描述

posted @ 2017-12-09 19:28  _吟游诗人  阅读(331)  评论(0编辑  收藏  举报