Mac下粗略实现ls命令
来源:互联网 发布:北京培训seo哪个好 编辑:程序博客网 时间:2024/05/23 13:03
- 文件结构
- main函数
- 命令行解析
- 输出结构字段
- 输出文件列表
- 读取目录结构
- getFileDetails
- 获取基本信息
- 组装文件属性
- 输出列表
- Makefile的编写
- 结果演示
- 代码链接
在*nix系统下,ls命令都是一个很重要的命令,用于某一文件夹中的文件列表,这个命令实现起来其实也十分简单,今天闲来无事,就在Mac上粗略的写写代码。
文件结构
不关注内部细节,ls的主要实现应该包括两个部分,一部分是参数解析,一部分是输出文件列表,所以我的项目文件结构如下所示:
main:程序入口点,调用输出列表函数
fileinfo:ls命令输出行model
parsecmd:该文件主要是参数解析部分,由于只是粗略的写写,并没有做什么检查,也只实现了ls中的-a和-l选项
dirhandler:该文件主要用于读取文件目录列表和文件相关信息。
main函数
首先来看看main函数中的代码,如下所示:
int main(int argc, const char * argv[]){ char* args = NULL; int argsCount = ParseCmds(argc, argv, args); int paths = argc - 1 - argsCount; if(paths == 0) showFilesWithArgs(".", args); else for(int i = argsCount + 1; i != argc; ++i) { if(paths > 1) printf("%s:\n", argv[i]); showFilesWithArgs(argv[i], args); } return 0;}
首先,解析参数,结束之后,如果发现用户没有指定目录,则将目录设置为当前目录,否则循环输出每个目录的信息。
命令行解析
由于只是粗略的解析一下,所以命令行解析也只是简单的将命令字符分离出来,代码如下所示:
int ParseCmds(int argc, const char* argv[], char*& args){ clean(args); args = (char*)malloc(sizeof(char) * ARGU_LEN); memset(args, 0, sizeof(char) * ARGU_LEN); int cmd_index = 0, argsCount = 0; for(int i = 1; i != argc; ++i) { const char* strp = *(argv + i); if((*strp) != '-') break ; ++argsCount; size_t arglen = strlen(strp); for(int j = 1; j != arglen; ++j) args[cmd_index++] = *(strp + j); } return argsCount;}
首先清空参数数组,然后为参数数组分配足够的空间,命令行都是以「-」开头,所以如果不是以该字符开头的命令字符串就不是命令选项了,而应该是目录,就是说命令已经解析完毕。否则将字符一个一个的存到args数组当中。
输出结构字段
fileinfo包含ls输出的各个字段,如下所示:
typedef struct FileInfo{ int fileType; int numberOfLinks; unsigned long fileSize; int abbreviatedMonth; int abbreviatedDayOfMonth; int abbreviatedHour; int abbreviatedMin; char* ownerName; char* groupName; char* fileName; char* fileProp; FileInfo* nextFile;}FileInfo;
- fileType:该文件的类型,比如常规文件,目录,字符设备等
- numberOfLinks:该文件所拥有的链接的数目
- abbreviated*:该文件的最后修改日期
- owerName:该文件的拥有者的名字
- groupName:该文件的拥有者所在组的名字
- fileName:该文件的名称
- fileProp:该文件的属性字段
- nextFile:用于保存下一个文件入口
输出文件列表
输出文件列表分为几个步骤:
- 读取目录结构,获取该目录下的所有文件名
- 读取各项文件的详细信息
- 填充fileinfo,组建属性字符串
- 根据命令行,输出相应结果
读取目录结构
*nix中提供了目录操作的相关函数,opendir, readdir, closedir,这三个函数用于打开目录入口,读取目录列表,关闭目录入口。读取目录列表将会返回一个dirent结构,描述目录的基本信息,代码如下所示:
if(chdir(path) == -1) { perror("chdir error"); return ; } DIR* dir = opendir(path); if(dir == NULL) { perror("open dir error"); return ; } struct dirent* _dirent = NULL; struct FileInfo* fileHeadPtr = NULL; while((_dirent = readdir(dir)) != NULL) { struct FileInfo* p = (struct FileInfo*)malloc(sizeof(struct FileInfo)); p->fileName = (char*)malloc(sizeof(char) * (_dirent->d_namlen + 1)); strcpy(p->fileName, _dirent->d_name); p->fileType = _dirent->d_type; if(fileHeadPtr == NULL) { fileHeadPtr = p; fileHeadPtr->nextFile = NULL; } else { p->nextFile = fileHeadPtr->nextFile; fileHeadPtr->nextFile = p; } if(args != NULL && strlen(args) != 0) getFileDetails(p); }
这段代码中主要做了4件事:
1. 读取并存储目录项信息
2. 构建目录链表
3. 保存文件名称及类型
4. 如果需要读取详细信息,则操作
getFileDetails
该函数主要用于获取目录项的详细信息,使用lstat函数来读取,该函数接收一个stat的结构,便于将详细信息存放在该结构中。关于stat结构请查看
获取基本信息
除了属性字符串需要特别组装以外,其他的信息都可以直接获取到,代码如下所示:
void getFileDetails(struct FileInfo*& info){ struct stat detail; if(lstat(info->fileName, &detail) == -1) { perror("lstat error"); return ; } info->numberOfLinks = detail.st_nlink; info->fileSize = detail.st_size; struct passwd* _passwd = getpwuid(detail.st_uid); info->ownerName = (char*)malloc(sizeof(char) * (strlen(_passwd->pw_name) + 1)); strcpy(info->ownerName, _passwd->pw_name); struct group* _group = getgrgid(detail.st_gid); info->groupName = (char*)malloc(sizeof(char) * (strlen(_group->gr_name) + 1)); strcpy(info->groupName, _group->gr_name); struct tm* _tm = localtime(&detail.st_mtimespec.tv_sec); info->abbreviatedMonth = _tm->tm_mon + 1; info->abbreviatedDayOfMonth = _tm->tm_mday; info->abbreviatedHour = _tm->tm_hour; info->abbreviatedMin = _tm->tm_min; info->fileProp = getFilePropStr(detail.st_mode); return ;}
其中,根据stat结构中的st_uid 和 st_gid,分别使用getpwduid和getgrgid两个方法,可以分别从返回的passwd和group结构中获取到文件属主名和文件属主所在的组。根据其中的st_mtimespec.tv_sec字段,可以获取到该文件的时间相关信息。
组装文件属性
getFilePropStr接收一个mode_t类型的数据,返回一个ls命令中的格式化字符串,而mode_t在stat结构中也早已拿到,根据mode_t,我们可以获取到文件的类型,文件的属主,属组和其他人所拥有的权限,代码如下所示:
char* getFilePropStr(mode_t mode){ char* prop = (char*)malloc(sizeof(char) * BUFSIZ); if(S_ISREG(mode)) prop[0] = '-'; else if(S_ISBLK(mode)) prop[0] = 'b'; else if(S_ISCHR(mode)) prop[0] = 'c'; else if(S_ISDIR(mode)) prop[0] = 'd'; else if(S_ISLNK(mode)) prop[0] = 'l'; else if(S_ISWHT(mode)) prop[0] = 'w'; else if(S_ISFIFO(mode)) prop[0] = 'p'; else if(S_ISSOCK(mode)) prop[0] = 's'; prop[1] = ((mode & S_IRUSR) == 0 ? '-' : 'r'); prop[2] = ((mode & S_IWUSR) == 0 ? '-' : 'w'); prop[3] = ((mode & S_IXUSR) == 0 ? '-' : 'x'); prop[4] = ((mode & S_IRGRP) == 0 ? '-' : 'r'); prop[5] = ((mode & S_IWGRP) == 0 ? '-' : 'w'); prop[6] = ((mode & S_IXGRP) == 0 ? '-' : 'x'); prop[7] = ((mode & S_IROTH) == 0 ? '-' : 'r'); prop[8] = ((mode & S_IWOTH) == 0 ? '-' : 'w'); prop[9] = ((mode & S_IXOTH) == 0 ? '-' : 'x'); return prop;}
输出列表
根据命令行,决定是短输出还是长输出,如代码所示:
void printLong(struct FileInfo* info){ printf("%s %d %s %s %lu %d %d %d:%d %s\n", info->fileProp, info->numberOfLinks, info->ownerName, info->groupName, info->fileSize, info->abbreviatedMonth, info->abbreviatedDayOfMonth, info->abbreviatedHour, info->abbreviatedMin, info->fileName); return ;}void printShort(char* fileName){ int printIndex = 0; bool bNeedTab = false; ++printIndex; printf(bNeedTab ? " %s" : "%s", fileName), bNeedTab = true; if(printIndex % LS_ITEMS_PER_LINE == 0) printf("\n"), bNeedTab = false; return ;}
至此,整个ls命令就编写完毕。
Makefile的编写
如果要在命令行下编译,我们知道,用makefile是相当不错的选择,虽然 只是寥寥几个文件,但一个make命令即能得到结果,也是不错的。其内容如下所示:
myls: main.cpp dirhandler.o parsecmd.o fileinfo.h g++ main.cpp dirhandler.o parsecmd.o -o mylsdirhandler.o: dirhandler.h dirhandler.cpp fileinfo.h g++ -c dirhandler.cpp fileinfo.hparsecmd.o: parsecmd.h parsecmd.cpp g++ -c parsecmd.cppclean: rm dirhandler.o parsecmd.o fileinfo.h.gch
这样一来,只要在命令行中输入make,即可得到我们所需要的myls命令,输出make clean即可以清理在make过程中产生的杂碎文件。
结果演示
演示结果如图所示:
额,似乎在最后做修改的时候,短输出的格式有点问题了
不过,不要在意这些细节,那都是浮云。重点还是命令的实现过程,虽然十分简单,但做为练练手的项目,打发打发时间还是相当不错的。
代码链接
github下载
- Mac下粗略实现ls命令
- Linux下ls命令实现
- Linux下ls命令的实现
- Linux下ls命令的简单实现
- 实现Linux下的ls命令
- 实现linux下的ls命令
- linux下实现ls -l命令
- Linux下用C++实现ls命令
- 简单实现ls命令
- ls命令的实现
- linux ls命令实现
- ls -l 命令实现
- ls 命令实现
- ls 命令的实现
- linux命令实现:ls
- 自己实现ls命令
- Linux ls命令实现
- 实现ls命令
- 数据结构实验之二叉树六:哈夫曼编码
- 【持久化框架】SpringMVC+Spring4+Mybatis3集成,开发简单Web项目+源码下载
- C++ String
- linux 查找大文件 大目录命令
- 获取sh shell 当前文件的绝对路径
- Mac下粗略实现ls命令
- 【前端笔试题】给定数字N,求从1到N中间0出现的次数
- Bootstrap框架快速上手攻略
- 2.DP数字三角形
- 快速排序(未)
- oracle检索出存在指定字段的所有表
- FP-Growth算法介绍
- jmeter JDBC运行报错Table 'performance_schema.session_variables' doesn't exist
- 布隆过滤器及Java实现