实现带有-a和-l参数的ls命令过程总结

实现ls命令(带有-a和-l参数)de过程总结


代码块

开心的贴代码时间

@galaxyxupt
#include<sys/types.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<sys/stat.h>
#include<unistd.h>
#include<dirent.h>
#include<grp.h>
#include<pwd.h>
#include<errno.h>
//#include<Linux/limits.h> 
--- 这个头文件被注释掉了一是因为我的ubuntu上找不到,二是貌似注释掉了也没什么影响
--- 还有就是本代码大部分借鉴于《Linux C 编程实战》第六章的编程实践部分,有部分改动

#define MAXROWLEN 150 //设置一行所能打印的字数

int g_leave_len = MAXROWLEN; //行剩余可用字数,最开始肯定为最大值,也就是行能容纳的字数
int g_maxlen; //获取的文件名中最长文件名的字数

void myerr(char *errstr,int line); //自定义的错误处理函数声明
void display_att(struct stat buf,char *name) //打印文件属性的函数
{
    char buf_time[50];
    struct passwd *psd;
    struct group * grp; //以上两个结构体包含在头文件中,无需自己定义
    if(S_ISLNK(buf.st_mode)) //判断是否为链接文件,ISLNK应该就是is link的意思,下面的自己推啦
        printf("l");
    else if(S_ISREG(buf.st_mode))
        printf("-");
    else if(S_ISDIR(buf.st_mode))
        printf("d");
    else if(S_ISCHR(buf.st_mode))
        printf("c");
    else if(S_ISBLK(buf.st_mode))
        printf("b");
    else if(S_ISFIFO(buf.st_mode))
        printf("f");
    else if(S_ISSOCK(buf.st_mode))
        printf("s");

    if(buf.st_mode&S_IRUSR) //与运算,嗯很神奇
        printf("r");
    else
        printf("-");
    if(buf.st_mode&S_IWUSR)
        printf("w");
    else
        printf("-");
    if(buf.st_mode&S_IXUSR)
        printf("x");
    else
        printf("-");

    if(buf.st_mode&S_IRGRP)
        printf("r");
    else
        printf("-");
    if(buf.st_mode&S_IWGRP)
        printf("w");
    else
        printf("-");
    if(buf.st_mode&S_IXGRP)
        printf("x");
    else
        printf("-");

    if(buf.st_mode&S_IROTH)
        printf("r");
    else
        printf("-");
    if(buf.st_mode&S_IWOTH)
        printf("w");
    else
        printf("-");
    if(buf.st_mode&S_IXOTH)
        printf("x");
    else
        printf("-");

    printf("    ");//

    psd = getpwuid(buf.st_uid);//终于看见汉字了,四不四很激动,上面那一串都差不多,大家自行理解就好,嘿嘿
    grp = getgrgid(buf.st_gid);//这两个函数可以分别通过uid和gid获取用户名和用户组名,返回一个结构体,至于为啥不直接返回字符指针我也想知道

    printf("%4ld",buf.st_nlink);//。。。这个buf可神奇了,里面啥都有。。。st_nlink是该文件的硬连接数
    printf("%-8s",psd->pw_name);//pw_name是用户名,可能是因为用户名在passwd里面吧
    printf("%-8s",grp->gr_name);//group这个单词认识吧,组名
    printf("%6ld",buf.st_size);//文件大小

    strcpy(buf_time,ctime(&buf.st_mtime));//获取最后一次被修改的时间时间。st_atime:最近一次被访问的时间。st_ctime:最近一次被更改的时间,
    buf_time[strlen(buf_time)-1] = '\0';//这个语句开始我是并不在意的,直到。。。打印出来的文件名全都换了行,开始还以为是行最大字数不够大,最后才知道ctime函数的返回值自带换行符。。。这个语句用'\0'覆盖掉'\n'。
    printf("    %s",buf_time);//打印时间

}

void display_sin(char *name)//打印单个文件名
{
    int i,len;
    if(g_leave_len < g_maxlen)//全局变量
    {
        printf("\n");//如果行剩余字数小于最大文件名的字数就换行,因为打印文件名的时候是按照最大文件名对齐的
        g_leave_len = MAXROWLEN;//换到下行后行剩余字数刷新为行最大字数
    }
    len = strlen(name);
    len = g_maxlen - len;//len的最终目的是要等于该文件名字数与最大文件名字数的差值,以便补上相应数量的空格使之对齐
    printf("%-s",name);//打印文件名

    for(i=0;i<len;i++)
        printf(" ");补齐空格
    printf("  ");//这个空格是每个文件名之间的间隔,设置为两个空格
    g_leave_len -= (g_maxlen+2);//每打印一次会消耗 最大文件名字数+2 个空格
}

void display(int flag,char * filename)//flag后面再讲,filename是绝对路径
{
    int i,j;
    char name[50];
    struct stat buf;//头文件自带结构体,存储文件的各种属性
    //从路径中截取文件名
    for(i=0,j=0;i<strlen(filename);i++)
    {
        if(filename[i]=='/')
        {
            j=0;
            continue;
        }
        name[j++] = filename[i];
    }
    name[j] = '\0';
    //上面这个就设计的很巧妙,这样循环,最后只能保存下来最后一个/后面的字符,也就是我们需要的文件名
    if(stat(filename,&buf)==-1)
            perror("lstat");
    //1:l 2:a 3:al or la 0:only  接受到的-l参数记作1,以此类推,感觉这样比书上的简单,0的话就说明没有接受到参数
    if(flag==0)//没有参数
    {   if(name[0]!='.')
            display_sin(name);//打印除了隐藏文件的文件名
    }
    else if(flag==1)//-l
    {   if(name[0]!='.')
            {
                display_att(buf,name);
                printf("    %-s\n",name);//打印除隐藏文件外的文件详细信息
            }
    }
    else if(flag==2)//-a
        display_sin(name);//打印全部文件名
    else if(flag==3)//-al or -la or -l -a
    {
        display_att(buf,name);
        printf("    %-s\n",name);//打印所有文件的详细信息
    }


}

void display_dir(int flag_param,char *path)//打印目录
{
    DIR *dir;
    int count=0;
    char filenames[256][50];//用二维数组保存文件名
    char tmp[50];
    struct dirent *ptr;

    //获取指定目录下文件总数和最长文件名长度
    dir = opendir(path);
    if(dir==NULL)
        myerr("opendir",__LINE__);
    while((ptr=readdir(dir))!=NULL)
    {
        if(g_maxlen<strlen(ptr->d_name))
            g_maxlen = strlen(ptr->d_name);//使g_maxlen始终保持最大
        count++;//计文件数
    }
    closedir(dir);
    if(count>256)
        myerr("files is too many",__LINE__);

    int len = strlen(path);
    dir = opendir(path);
    for(int i=0;i<count;i++)
    {
        ptr = readdir(dir);
        if(ptr==NULL)
            myerr("readdir",__LINE__);
        strncpy(filenames[i],path,len);
        filenames[i][len] = '\0';
        strcat(filenames[i],ptr->d_name);//上面三步通过将路径和文件名拼接制造出绝对路径
        filenames[i][len+strlen(ptr->d_name)] = '\0';//最后补'\0'
    }

    //冒泡对文件名排序,没啥说的,就是注意补'\0'
    for(int i=0;i<count;i++)
        for(int j=0;j<count-1;j++)
        {
            if(strcmp(filenames[j],filenames[j+1])>0)
            {
                strcpy(tmp,filenames[j]);
                tmp[strlen(filenames[j])] = '\0';
                strcpy(filenames[j],filenames[j+1]);
                filenames[j][strlen(filenames[j+1])] = '\0';
                strcpy(filenames[j+1],tmp);
                filenames[j+1][strlen(tmp)] = '\0';
            }
        }

    for(int i=0;i<count;i++)
        display(flag_param,filenames[i]);

    closedir(dir);
}

void myerr(char *errstr,int line)
{
    fprintf(stderr,"line:%d",line);
    perror(errstr);
    exit(1);
}



//终于开始的主函数。。。
int main(int argc,char** argv)
{
    char path[100] = "./";
    char param[20];
    struct stat buf;
    int flag=0,flag2=0;

    for(int i=1;i<argc;i++)
    {
        if(argv[i][0]=='-')
        {
            for(int j=1;j<1+strlen(argv[i]);j++)
            {
                if(argv[i][j]=='l')
                {
                        if(flag==2)//判断是否已经接收到-a,如果接收到,则设置flag=3,下面的同理
                            flag = 3;
                        else if(flag==0)//说明没有接收到其他参数
                            flag = 1;
                }
                if(argv[i][j]=='a')
                {
                        if(flag==1)
                            flag = 3;
                        else if(flag==0)
                            flag = 2;
                }
            }
        }
        else
        {
            strcpy(path,argv[i]);
            path[strlen(argv[i])] = '\0';//注意补'\0'
            flag2 = 1;
        }
    }

    if(flag2==0)//flag2为零,说明没有接受到参数,则直接打印当前目录
        display_dir(flag,path);

    if(stat(path,&buf)==-1)//无效路径
        myerr("stat",__LINE__);

    //接下来判断是目录文件还是其他文件
    if(S_ISDIR(buf.st_mode))
    {
        if(path[strlen(path)-1]!='/')
        {
            path[strlen(path)] = '/';
            path[strlen(path)+1] = '\0';
        }
        else
            path[strlen(path)] = '\0';//确保路径名以/结尾
        display_dir(flag,path);
    }
    else 
    {
        display(flag,path);
    }
}

要说的话都在代码里面了,没看的话去上面?啊哈,告辞!!!

End

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值