linux_shell之ls部分功能实现

来源:互联网 发布:明星淘宝店叫什么名字 编辑:程序博客网 时间:2024/05/20 10:53

主要实现以下功能:

ls:显示当前目录下的所有文件(不含隐藏文件)

ls -a:显示当前目录下的所有文件(含隐藏文件)

ls -l:显示当前目录下的所有文件的详细信息

ls -R:显示当前目录下的文件及其子目录下的所有文件

 

 

通过实现代码相应的总结:

1.考虑各个选项对结果的控制,考虑将文件信息保存在一个全局数组当中,这样,可以根据后面各个选项的要求进行对格式信息的调整,可以通过控制这个信息数组,可以实现绝大多数选项功能,但是在进行-R选项功能的时候出现了问题,所以在本次实现中,其他的3个选项是基于同一个查询,-R则另外根据了一个查询,这里日后如果有其他好的方法可以改下,目前暂时没有什么思路。

2.关于选项的控制,这里呢,是用一个数组来保存相应的选项开关的,如果命令中出现该选项,则对应项为1,反之,对应项为0,这样在后面检测的时候就可以根据相应的位置是否为1来进行相应的分流操作,这样的好处是不需要进行硬性的字符串比较,真正的ls也肯定不是进行字符串比较的,这里是仿ls进行的操作。不论选项如果排列,是分开还是合在一起,抑或重复出现,都是可以进行处理的。

3.原先以为ls -R使用了栈结构来遍历文件目录,后来发现还是用的递归遍历数组,这样的话,在很大程度上现在的实现已经基本符合了,现在唯一要考虑的就是信息该如何保存并显示,是该存在一个全局变量中,还是一个局部变量中,是查到一项就输出,还是全部查好之后在输出,这都是可以考虑的地方。

4.这里也没有考虑文件名长度是否能够容纳的问题,而是分配的一个数组来存储相应的文件名字的,后续可以考虑结合动态内存分配。


附上代码:

#include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <sys/stat.h>#include <unistd.h>#include <string.h>#include <time.h>#define MAX_COUNT 100 //总共能够统计的文件项数,用这个值去分配保存信息的数组的大小#define FILE_LENGTH_MAX 20 // 自定义的一个文件的最长长度。enum EOPT{ E,E_a,E_l,E_r,E_num}; // 相应的控制选项,E为ls,E_a为ls -a,E_r为ls -R,E_l为ls -lint getOPT[E_num] = {0}; // 一个保存相应选项的状态数组typedef struct{mode_tst_mode;uid_tst_uid;gid_tst_gid;off_tst_size;nlink_tst_nlink;char*fname;struct timespecst_time;}fileInfo; // 由于很多信息在这里没用,所以自定义了一个文件项信息结构static fileInfo* fInfo; // 所有的函数通过这个指针对查询结果进行操作static int fileCount; // 统计目前已经统计了多少个文件项int query(char*); // 普通查询,将结果存于fInfo数组中int query_r(char*); // 递归遍历查询int isHideFile(const char*); // 判断是否是隐藏文件void print(); // 没有-l选项的打印void printl();  // 附加-l选项void printInfo(const fileInfo);int getmode(const char*); // 获取相应选项信息void rprintl(const char*,struct stat); // 递归遍历中的附加-l选项打印void rprint(const char*); // 递归遍历中的普通打印int main(int argc,char *argv[]){char buf[1024]; // 用来保存文件名//getcwd(buf,1024);if(argv[argc-1][0] == '-' || argc == 1)getcwd(buf,1024);elsestrcpy(buf,argv[argc-1]);int i = 1;for(;i<argc;i++)getmode(argv[i]);if(getOPT[E_l]!=1) // 如果没有指定-l,默认就是不打印文件的详细信息getOPT[E] = 1;if(getOPT[E_r] == 0){query(buf);if(getOPT[E_l] == 1)printl();elseprint();}elsequery_r(buf);return EXIT_SUCCESS;}int getmode(const char* arg) // 将相应的选项变为1{if(arg[0]!='-')return -1;const char *p;p = &arg[1];while(*p!=0){if(*p == 'a')getOPT[E_a] = 1;else if(*p == 'l')getOPT[E_l] = 1;else if(*p == 'R')getOPT[E_r] = 1;p++;}return 0;}int query(char* pathname){fInfo = (fileInfo*)malloc(sizeof(fileInfo)*MAX_COUNT);if(fInfo == NULL){printf("fInfo allocate error\n");return -1;}struct dirent *dirp;DIR *dp;struct stat bufstat;fileInfo *tmp = fInfo;if((dp = opendir(pathname)) == NULL){printf("opendir error\n");return -1;}while((dirp = readdir(dp))!=NULL){fileCount++;strcpy(&pathname[n],dirp->d_name);if(lstat(pathname,&bufstat) < 0){printf("lstat error\n");return -1;}tmp->fname = (char*)malloc(sizeof(char)*(strlen(dirp->d_name)+1));strcpy(tmp->fname,dirp->d_name);tmp->st_mode = bufstat.st_mode;tmp->st_uid = bufstat.st_uid;tmp->st_gid = bufstat.st_gid;tmp->st_size = bufstat.st_size;tmp->st_nlink = bufstat.st_nlink;tmp->st_time = bufstat.st_ctim;tmp++;}pathname[n-1] = 0;closedir(dp);return 0;}int isHideFile(const char*pathname){if(pathname[0] == '.')return 1;elsereturn 0;}void print() {int i = 0;for(;i<fileCount;i++){if(getOPT[E_a] == 0 && isHideFile(fInfo[i].fname)) // 如果没有指定-a选项,并且当前文件为隐藏文件,则跳过continue;printf("%s\n",fInfo[i].fname);}}void printl(){int i = 0;for(;i<fileCount;i++){if(getOPT[E_a] == 0 && isHideFile(fInfo[i].fname))continue;printInfo(fInfo[i]);printf("\n");}}void printInfo(const fileInfo file) // 打印详细的信息,这里是仿windows下的信息显示{struct tm *p;p = gmtime(&(file.st_time.tv_sec));printf("%d/%d/%d\t%d:%d:%d\t",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);if(S_ISDIR(file.st_mode))printf("\t<DIR>\t\t");elseprintf("\t\t\t");printf("%s",file.fname);}int query_r(char* pathname){struct dirent *dirp;DIR * dp;struct stat bufstat;if((lstat(pathname,&bufstat)) < 0){printf("lstat error\n");return -1;}if(S_ISDIR(bufstat.st_mode) == 0) {// 对普通文件进行处理if(getOPT[E_l] == 1)rprintl(pathname,bufstat);elserprint(pathname);return 0;}int n = strlen(pathname);pathname[n++] = '/';pathname[n] = 0;if((dp = opendir(pathname)) == NULL){printf("opendir error\n");return -1;}printf("%s:\n",pathname);while((dirp = readdir(dp)) != NULL){if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0) // 跳过递归遍历.和..防止死循环{if(getOPT[E_a] == 1 && getOPT[E] == 1)       printf("%s\n",dirp->d_name);if(getOPT[E_a] == 1 && getOPT[E_l] == 1)rprintl(dirp->d_name,bufstat);continue;}strcpy(&pathname[n],dirp->d_name);query_r(pathname);}pathname[n] = 0;closedir(dp);}const char* func(const char* pathname) // 去除文件名前相应的路径{if(pathname[0] == '.')return pathname;const char*p = &pathname[strlen(pathname)-1];while(*p!='/')--p;return p+1;}void rprintl(const char*pathname,struct stat bufstat){struct tm *p;p = gmtime(&(bufstat.st_ctim.tv_sec));printf("%d/%d/%d\t%2d:%2d:%2d\t",(1900+p->tm_year),1+p->tm_mon,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);printf("\t\t%s\n",func(pathname));}void rprint(const char* pathname){printf("%s\n",func(pathname));}


0 0
原创粉丝点击