Unix类ls的小程序

来源:互联网 发布:json字符串base64加密 编辑:程序博客网 时间:2024/05/16 08:17

【基本功能】
(1)与 ls 命令类似,命令行参数可以有 0 到多个
0 个参数:列出当前目录下所有文件
参数为普通文件:列出文件
参数为目录:列出目录下所有文件
(2)实现自定义选项 r,a,l,h,m 以及–r 递归方式列出子目录
a 列出文件名第一个字符为圆点的普通文件(默认情况下不列出
文件名首字符为圆点的文件)
l 后跟一整数,限定文件大小的最小值(字节)
h 后跟一整数,限定文件大小的最大值(字节)
m 后跟一整数 n,限定文件的最近修改时间必须在 n 天内
– 显式地终止命令选项分析
【程序源码】

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<errno.h>#include<dirent.h>#include<sys/stat.h>char mPath[50];//用户输入的路径const int _end=5;const int _r = 0;const int _a = 1;const int _l = 2;const int _h = 3;const int _m = 4;int switch_order(int argc, char **argv);//分解参数,成功则返回0,否则返回-1int execute_order();//执行指令,成功则返回0,否则返回-1void show_info(const struct dirent *entry,struct stat st);/***********指令**************   共有6个额外的可选指令                         **   -r 递归方式列出子目录*   -a 列出文件名第一个字符为圆点的普通文件*   -l 后跟一整数,限定文件大小的最小值(字节)*   -h 后跟一整数,限定文件大小的最大值(字节)*   -m 后跟一整数n,限定文件的最近修改时间必须在n天内*   --显式地终止命令选项分析****************************/int mOrder[6] = { 0 };//指令默认为空long mMax_size;//最大文件尺寸long mMin_size;//最小文件尺寸time_t mDays_limit;//-m的时间限制,另外,time_t其实是long的别名time_t mCurrent_time;int main(int argc, char **argv){    //DIR *dir;    if(switch_order(argc, argv)==0){//如果转换指令成功        execute_order(mPath);    }    // dir = opendir(argv[1]);    // if (dir == NULL) {    //     printf("Open directory \"%s\": %s (ERROR %d)\n",    //         argv[1], strerror(errno), errno);    //     return 1;    // }     // printf("entry->d_ino\tentry->d_name\tentry->d_type\n" );    // while ((entry = readdir(dir)) != NULL){    //     printf("%4d %s %s\n", entry->d_ino, entry->d_name,entry->d_type);    // }    // closedir(dir);    return 0;}int switch_order(int argc, char **argv){    time(&mCurrent_time);//获取指令执行时的时间    if (argc == 1) {//目前的指令数目不足(没有参数是1,这里没有参数是不允许的)        printf("the num of the order is not enough\n");        system("pause");        return 1;    }    int i = 0;    int j = 0;    while (i <= argc - 2){//参数紧跟在命令之后,目录在最后面,共有argc-1个参数,减去目录共有argc-2个        if (argv[++i][0] == '-'){//检测到是指令            switch (argv[i][1]){            case 'r':                mOrder[_r] = 1;                break;            case 'a':                mOrder[_a] = 1;                break;            case 'l':                mOrder[_l] = 1;                if ((mMin_size = atol(argv[++i])) == 0){                    printf("something wrong with \"-l\" in the order\n");                    system("pause");                    return 1;                }                break;            case 'h':                mOrder[_h] = 1;                if ((mMax_size = atol(argv[++i])) == 0){                    printf("something wrong with \"-h\" in the order\n");                    system("pause");                    return 1;                }                break;            case 'm':                mOrder[_m] = 1;                if ((mDays_limit = atol(argv[++i])) == 0){                    printf("something wrong with \"-m\" in the order\n");                    system("pause");                    return 1;                }                break;            case '-':                mOrder[_end] = 1;                break;            }        }        else{            //不是-开头则认为是路径             strcpy(mPath, argv[i]);        }    }    printf("path is %s\n",mPath);    return 0;//linux return 0表示运行成功}/********************************执行指令,如果成功则返回0,失败则返回1********************************/int execute_order(const char *path){//传入一个path     int ret;    struct stat st;    struct dirent *entry;//目录里文件的读取指针    char current_path[50];    ret = stat(path, &st);    DIR *dir;    if(ret==0){        if(S_ISDIR(st.st_mode)){            //如果是目录            dir=opendir(path);            if(dir==NULL){                //读取失败                printf("Open dir \"%s\" :%s,ERROR(%d)\n",path,strerror(errno),errno);                return 1;            }            while((entry=readdir(dir))!=NULL){                //这里需要特别注意一下                 //entry中会出现当前文件夹和上层文件夹的目录索引 很明显这并不是我们想要的                //所以这里需要特别注意一些                char* current_dir_string=".";                char* parent_dir_string="..";                if(strcmp(entry->d_name,current_dir_string)!=0&&strcmp(entry->d_name,parent_dir_string)!=0){//如果并不是当前目录                    //获取当前文件夹下面的各个文件的stat                    strcpy(current_path,path);                    strcat(current_path,"/");                    strcat(current_path,entry->d_name);                    ret=stat(current_path,&st);                    // printf("%s\n",current_path);                    if(ret==0){ //如果成功获取了stat                        show_info(entry,st);                        if(S_ISDIR(st.st_mode)){//如果当前文件是文件夹                            if(mOrder[_r]&&!mOrder[_end]){//如果是递归                                execute_order(current_path);                            }                        }                    }                    else{//失败则返回原因                        printf("Read file \"%s\" :%s,ERROR(%d)\n",path,strerror(errno),errno);                    }                }            }            closedir(dir);        }        else{//如果这只是一个文件罢了            printf("%d\t%d\n",st.st_size,st.st_mtime);        }    }        return 0;}/*******************用来对内容进行过滤*******************/void show_info(const struct dirent* entry,struct stat st){    //对文件进行选择性过滤    // int count;    // for(count=0;count<6;count++){    //     printf("%d : %d\n",count,mOrder[count]);    // }    // printf("%d  %d\n",_end,mOrder[_end]);    if(mOrder[_end]==0){        if(mOrder[_a]||entry->d_name[0]!='.'){//默认的情况下以‘.’开头的文件并不会显示出来            if(!mOrder[_l]||st.st_size>mMin_size){                if(!mOrder[_h]||st.st_size<mMax_size){                    if(!mOrder[_m]||((mCurrent_time-st.st_mtime)/86400)<mDays_limit){                        printf("%d\t%d\t%s\n",st.st_size,st.st_mtime,entry->d_name);                    }                }            }        }            }    else{              printf("%d\t%d\t%s\n",st.st_size,st.st_mtime,entry->d_name);        }}

【运行效果】
<1>基本指令(路径)
这里写图片描述

<2>进行最大文件过滤
这里写图片描述

<3>进行最小文件过滤
这里写图片描述

<4>日期过滤
这里写图片描述

<5>递归显示所有文件
这里写图片描述

<6>单个文件测试
这里写图片描述

<7>综合测试
这里写图片描述

<8>终止指令测试
这里写图片描述

【存在的问题】
程序的功能虽然基本实现了,但是程序编写时一些疑惑没有解决。比如,使用了全局变量来保存用户指令,偶尔在编译之后会出现异常。
Const int _i=5在之前的时候命名是const int _end=5。但是非常蹊跷的是,在main函数的开头处打印这个数值,显示的是1!这修改了常量的名称之后又恢复了正常。
(此处怀疑是头文件中的全局变量出现了_end这个常量?但是在我后来的修改中这一问题又消失了)
还有,在show_info()函数中,如果想转换时间戳为字符串格式时。printf(“%d\t%s\t%s\n”,st.st_size,ctime(st.st_mtime),entry->d_name);
在编译过程中不会出错,但是很蹊跷得在运行时显示segment fault。这本是风马牛不相及的错误。
Gcc编译器的调试对我依然很难。第一个问题可能很难再现了。第二个问题希望有人可以和我探讨一下514201942@qq.com

0 0
原创粉丝点击