Unix类ls的小程序

【基本功能】
(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,否则返回-1
int execute_order();//执行指令,成功则返回0,否则返回-1
void 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值