ls实现( 包含 颜色 -a -l -r -R -i -s等)

ls 命令的实现需要不断的在函数之间调用,所以一定要把握住每个函数要的参数
实现-a -l -R等参数的思想
1、-a需要显示出所有的文件 ,包括隐藏文件,所以ls 和 ls -a的区别就在于显不显示隐藏文件
2、-l需要显示出文件的详细信息,不包括隐藏文件,所以需要去获取到文件的信息(通过函数 lstat(const char *name,struct stat buf)获取文件属性信息,获取成功返回0,失败返回-1),然后去打印出需要的文件信息
3、-R是递归显示文件,自然需要函数递归去打印所要的东西
4、给打印的不同文件类型加上不同的颜色: 去判断文件的类型,然后去返回一个常数,通过颜色打印函数去输出,所以舍弃掉原有的printf,自己去写一个 printf_name

最重要的需要去熟悉每一个函数的功能,不同函数间的不断调用可能会显得很复杂,扰乱了你自己。
在这里插入图片描述

如果要实现-a -l 需要4个函数

1、display_single :
功能: 输出文件名
实现:只需要一个打印函数,再去保证上下对齐。
参数:需要打印,所以需要文件名,只要传入文件名即可。。。。(char *name)
2、display_attribute:
功能:显示文件的详细信息。
实现:需要打印出很多的信息,所以也是很多的打印函数
参数:因为struct stat buf 是一个保存文件状态信息的结构体,所以可以用它来打印出文件信息。所以需要一个buf参数,而buf并没有保存文件名,所以还需要一个字符指针 。。。。 (struct stat buf ,char *name)
3、display_dir:
功能:打开该目录,保存下该目录下所有的文件名,为显示某个目录下的文件做准备。
实现:打开该目录,将文件名导入一个字符数组,并display
参数:因为需要将命令行参数交给display去转换,所以需要一个保存命令行参数的值,并且需要得到要打开的路径 。。。。(int flag,char * path)
4、 display:
功能:根据命令行参数,和完整路径名显示目标文件。
实现:通过一个switch语句,转换命令行参数,跳转到不同的函数,去进行输出。
参数:命令行参数和完整路径名(int flag , char * pathname).

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

增加参数

1、屏蔽ctrl + c 杀死程序
只需要一行代码:signal(SIGINT,SIG_IGN);
2、display_dir_R:递归调用
在这里插入图片描述
3、注意权限问题:
如果错误号是13,就是因为权限不够导致的程序异常退出,所以应该排除掉权限不够导致的错误,所以每次去获取信息,都应该屏蔽掉权限不够的错误
4、对于display_single新增的参数:
是因为其他的命令行参数进行调用时,需要那些信息,所以只好加上。

#include<stdio.h>
#include<stdio.h>
#include<signal.h>
//用来屏蔽Ctrl+c杀死程序
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<dirent.h>
#include<grp.h>
#include<pwd.h>
#include<errno.h>
#include<sys/stat.h>
#include<limits.h>


//颜色参数
#define WHITE 0
#define BLUE  1
#define GREEN 2
#define RED   3
#define LBLUE 4
#define YELLOW 5

//命令行参数
#define PARAM_NONE 0
#define PARAM_A    1
//-a 显示所有文件
#define PARAM_L    2
//-l 一行只显示一个文件的详细信息
#define PARAM_R    4
//-R 递归打开目录显示文件
#define PARAM_r    8
//-r 倒序显示文件
#define PARAM_F    16
//-F 识别文件类型 ,加上标识符
#define PARAM_i    32
//-i 查看文件的inode号
#define PARAM_s    64
//显示文件大小

//设置每行最多的字符数为80
#define MAXROWLEN  80



int g_leave_len = MAXROWLEN; //一行剩余长度,用于输出对齐
int g_maxlen;                //存放某目录下最长文件名的长度


void printf_name(char *name,int color); //带有不同颜色的打印文件名
int get_color(struct stat buf);         //不同文件类型得到不同颜色型号
void display_dir(int flag_param,char *path);
//为显示某个目录下的文件做准备
void display_dir_R(int flag,char *name);
//递归打开目录
void display_attribute(struct stat buf,  char *name);
//打印名为name的文件信息
void display_single(int flag,struct stat buf,char *name,int color);
//输出文件的文件名
void display(int flag,char *pathname);
//根据命令行参数flag和完整路径名,显示目标文件

int main(int argc,char  *argv[])
{
    signal(SIGINT,SIG_IGN);
    //屏蔽ctrl+c杀死程序
    int i,j,k,num;
    char path[PATH_MAX+1];
    char param[32];    //保存命令行参数,目标文件名和目录名不在此列
    int flag_param = PARAM_NONE; //参数种类,默认为0
    struct stat buf;
    j=0;
    num=0;
    //对命令行参数进行解析,提取到param数组中
    for(i=1;i<argc;i++)
    {
        if(argv[i][0] == '-')
        {
            for(k=1;k<strlen(argv[i]);k++,j++)
            {
                param[j] =argv[i][k]; //获取-后面的参数保存到数组param中

            }
            num++;         //保存 - 的个数
        }
    }

    //让flag_param 得到总参数,并对错误命令行参数进行筛选
    for(i=0;i<j;i++)
    {
        if(param[i] == 'a')
        {
            flag_param |=PARAM_A;
            continue;
        }
        else if(param[i] == 'l')
        {
            flag_param |=PARAM_L;
            continue;
        }
        else if(param[i] =='R')
        {
            flag_param |=PARAM_R;
        }
        else if(param[i] == 'r')
        {
            flag_param |=PARAM_r;
        }
        else if(param[i] == 'F')
        {
            flag_param |= PARAM_F;
        }
        else if(param[i] == 'i')
        {
            flag_param |= PARAM_i;
        }
        else if(param[i] == 's')
        {
            flag_param |= PARAM_s;
        }
        else 
        {
            printf("my_ls :invalid option -%c \n",param[i]);
            exit(1);

        }

    }
    param[j]='\0';
    //如果没有输入路径,就设置为当前路径
    if((num+1) == argc)
    {
        strcpy(path,"./");
        path[2]='\0';
        display_dir(flag_param,path);
        return 0;
    }
    i=1;
    do
    {
        //如果不是目标文件名或目录,解析下一个命令行参数
        if(argv[i][0] == '-')
        {
            i++;
            continue;
        }
        else 
        {
            strcpy(path,argv[i]);


            //如果目标文件或目录不存在,报错并退出程序
            if(stat (path,&buf) == -1)
                perror("stat fail:");
            //判断该路径是不是目录
            if(S_ISDIR(buf.st_mode))   
            {
                //是目录但是没带 '/'就加上'/'
                if(path[strlen(argv[i])-1] !='/')
                {
                    path[strlen(argv[i])]='/';
                    path[strlen(argv[i])+1] ='\0';
                }
                
                if(flag_param & PARAM_R)
                {
                    display_dir_R(flag_param,path);
                }
                else            //argv[i]是一个文件
                    display_dir(flag_param,path);
                
                i++;
                
            }
            else
            {
                display(flag_param,path);
                i++;
            }
            

        }
    }while(i<argc);
    return 0;
}
void display_attribute(struct stat buf,  char *name)
{
	char buf_time[32];
	struct passwd *psd;      //从该结构体中获取文件所有者的用户名
    struct group *grp;       //从该结构体中获取文件所有者所属组的组名
	
    //获取并打印文件类型
	if(S_ISLNK(buf.st_mode))
	{
		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("  ");

//根据uid与gid获取文件所有者的用户名与组名
    psd = getpwuid(buf.st_uid);
    grp = getgrgid(buf.st_gid);
    printf("%4d",buf.st_nlink);  //打印文件的链接数
    printf("%-8s",psd->pw_name);
    printf("%-8s",grp->gr_name);
    printf("%6d",buf.st_size);   //打印文件的大小
    strcpy(buf_time,ctime(&buf.st_mtime));
    buf_time[strlen(buf_time)-1]='\0';    //去掉换行符
    printf(" %s",buf_time);               //打印文件的时间信息
    	
}
void display_single(int flag,struct stat buf,char *name,int color)
{
    int i,len;
    if(flag & PARAM_s)
    {
        printf("%-8d",buf.st_blocks);
        printf_name(name,color);
        printf("\n");
    }
    //判断是否带有i参数
    else if(flag & PARAM_i)
    {
        printf("%-8d",buf.st_ino) ;
        printf_name(name,color);
        printf("\n");
    }
    else
    {

    
        if(g_leave_len<g_maxlen)
        {
            printf("\n");
            g_leave_len = MAXROWLEN;
        }
        len = g_maxlen - strlen(name);
        printf_name(name,color);
        //判断是否带有参数F
        if(flag & PARAM_F)
        {
            //链接文件在文件名后加@
        if(S_ISLNK(buf.st_mode))
            printf("@");
            //管道文件后面加|
        else if(S_ISFIFO(buf.st_mode))
            printf("|");
            //目录后面加/
        else if(S_ISDIR(buf.st_mode))
            printf("/");
            //套接字后面加=
        else if(S_ISSOCK(buf.st_mode))
            printf("=");
        else 
            printf(" ");
        }
        for(i=0;i<len;i++)
        {
            printf(" ");
        }
        printf("  ");
        g_leave_len -= (g_maxlen+3);
    }
}
//根据命令行参数和完整路径名显示目标文件
//参数flag:命令行参数
//参数pathname:包含了文件名的路径名
//
void display(int flag,char *pathname)
{
    int i,j;
    struct stat buf;
    char name[NAME_MAX+1];

    //过滤掉路径,仅保留文件名到name
    //从路径中解析出文件名
    for(i=0,j=0;i<strlen(pathname);i++)
    {
        if(pathname[i] == '/')
        {
            j=0;
            continue;

        }
        name[j++]=pathname[i];

    }
    name[j] = '\0';
    //用lstat而不是stat以方便解析链接文件
    if(lstat(pathname,&buf) == -1)
        
    {
        //过滤掉权限不够的错误
        if(errno !=13)
            perror("opendir ");
        else 
            return ;
    }
    int color = get_color (buf);
    switch(flag)
    {
        case PARAM_NONE:
            if(name[0]!='.')
                display_single(flag,buf,name,color);
            break;

        case PARAM_A:
            display_single(flag,buf,name,color);
            break;
        
        case PARAM_L:
            if(name[0]!='.')
            {
            display_attribute(buf,name);
            printf("%-s\n",name);
            }
            break; 
        
        case PARAM_F:
            if(name[0]!='.')
        {
            display_single(flag,buf,name,color);
            break;
        }
        
        case PARAM_i:
            if(name[0]!='.')
            {
                display_single(flag,buf,name,color);
            }
        break;
        
        case PARAM_s:
            if(name[0]!='.')
        {
            display_single(flag,buf,name,color);
        }
        break;
        
        case PARAM_r:
            if(name[0]!='.')
        {
            display_single(flag,buf,name,color);
            break;
        }
        
        case PARAM_R:
            if(name[0]!='.')
            {
                display_single(flag,buf,name,color);
            }
            break;
        
        case PARAM_R+PARAM_A:
            display_single(flag,buf,name,color);
            break;
        
        case PARAM_L+PARAM_R:
            if(name[0]!='.')
            {
                display_attribute(buf,name);
            }
            break;
        
        case PARAM_L+PARAM_A:
            display_attribute(buf,name);
            break;
        
        case PARAM_L+PARAM_A+PARAM_R:
            display_attribute(buf,name);
            break;
        
        default:
            break;
    }
}
void display_dir(int flag_param,char *path)
{
    
    DIR *dir;
    g_leave_len=80;
    struct dirent *ptr;
    int count = 0;
    char filenames[256][PATH_MAX+1],temp[PATH_MAX+1];
    //获取该目录下文件总数和最长的文件名
    dir = opendir(path);
    if(dir == NULL)
    {
        //因为有多层函数调用,所以每一次都要过滤掉权限不够的错误
        if(errno!=13)
            perror("opendir fail");
        else
            return ;
    }
    //找到最长文件名,并且统计文件个数
    while((ptr = readdir(dir ))!=NULL)
    {
        if(g_maxlen< strlen(ptr->d_name))
            g_maxlen = strlen(ptr->d_name);
        count ++;

    }
    if(count >256)
    {
        printf("too many files under this dir\n");
        exit(0);
    }
    closedir(dir);
    int i,j;
    dir = opendir(path);
    if(dir == NULL)
        perror("opendir fail:");
    int len=strlen(path);
    //获取该目录下所有的文件名
    for(i=0;i<count;i++)
    {
        ptr = readdir(dir);
        if(ptr == NULL)
            perror("readdir fail:");
        strncpy(filenames[i],path,len);
        filenames[i][len] = '\0';
        strcat(filenames[i],ptr->d_name);
        filenames[i][len+strlen(ptr->d_name)] = '\0';
    }

    //冒泡法排序,排序后文件名按字母顺序存储于filenames
    for(i=0;i<count -1;i++)
    {
        for(j=0;j<count-1-i;j++)
        {
            if(strcmp(filenames[j],filenames[j+1])>0)
            {
                strcpy(temp,filenames[j+1]);
                temp[strlen(filenames[j+1])] = '\0';
    
                strcpy(filenames[j+1],filenames[j]);
                filenames[j+1][strlen(filenames[j])] = '\0';
                
                strcpy(filenames[j],temp);
                filenames[j][strlen(temp)] = '\0';
            }
        }
    }

    //-r   逆序输出
    if(flag_param & PARAM_r)
    {
        for(i=count-1;i>=0;i--)
            display(flag_param,filenames[i]);
    }
    else    //不带参数-r,正序输出
        for(i=0;i<count ;i++)
            display(flag_param,filenames[i]);

    closedir(dir);

    //如果命令行中没有-l选项,打印一个换行符
    if((flag_param &PARAM_L) == 0)
        printf("\n");
}
void display_dir_R(int flag,char *name)
{
    DIR *dir;
    struct dirent *ptr;
    char temp_name[PATH_MAX+1];
    printf("%s:\n",name);
    
    display_dir(flag,name);
    printf("\n");
    
    if((dir = opendir(name)) == NULL)
    {
        if(errno!=13)
            perror("display_R fail:");
        
        else 
            return ;
    }
    int len = strlen(name);
    while((ptr = readdir(dir ))!=NULL)
    {
        if(ptr->d_type == DT_DIR && (ptr -> d_name[0]!='.'))
        {
            strncpy(temp_name,name,len);
            temp_name[len] = '\0';
            
            strcat (temp_name,ptr->d_name);
            temp_name[len+strlen(ptr->d_name)] = '/';
            
            temp_name[len+strlen(ptr->d_name)+1] = '\0';
            display_dir_R(flag,temp_name);
        }
    }
    closedir(dir);
    return ;
}

//对不同的文件类型给不同的颜色
int get_color(struct stat buf)
{
    int color = 0;
    if(S_ISLNK(buf.st_mode))
    {
        color = LBLUE;
    }
    else if(S_ISDIR(buf.st_mode))
    {
        color = BLUE;
    }
    else if(S_ISCHR(buf.st_mode) ||S_ISBLK(buf.st_mode) )
    {
        color = YELLOW;
    }
    else if(buf.st_mode & S_IXUSR)
    {
        color = GREEN;
    }
    return color;
}

void printf_name(char *name,int color)
{
    if(color == GREEN)
    {
        printf("\033[1m\033[32m%-s\033[0m",name);
    }
    else if(color == BLUE)
    {
        printf("\033[1m\033[34m%-s\033[0m",name);
    }
    else if(color == WHITE)
    {
        printf("%-s",name);
    }
    else if(color == LBLUE)
    {
        printf("\033[1m\033[36m%-s\033[0m",name);
    }
    else if(color == YELLOW)
    {
        printf("\033[1m\033[33m%-s\033[0m",name);
    }
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值