实验6-LINUX环境编程-2(12页).doc
-实验6- LINUX环境编程-2-第 12 页实验6、LINUX环境编程 -2学生姓名: 李亚军 学 号: 6100412196 专业班级: 卓越计科121班 1实验目的 结合文件操作,理解LINUX环境中的命令行参数的使用 。2实验内容 1编写LINUX C程序,实现简单的LINUX命令ls功能。3实验步骤 #include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <string.h>#include <sys/stat.h>#include <memory.h>#include <malloc.h>#include <getopt.h>#include <grp.h>#include <pwd.h>#include <unistd.h>#include <fcntl.h>#include <time.h>#include <error.h>#include <sys/types.h>#include <linux/kdev_t.h> #define OPT_v 0x0001 /* -v 选项:查看本软件版本 */#define OPT_h 0x0002 /* -h 选项:查看本软件帮助 */#define OPT_l 0x0004 /* -l 选项:长型(long)显示 */#define OPT_a 0x0008 /* -a 选项:显示所有文件(all)*/#define OPT_R 0x0010 /* -R 选项:显示子目录内容 */#define OPT_f 0x0020 /* -f 选项:不排序 */#define DONE_SUCCESS 0typedef struct _Node char path1024; char name256; int length; struct stat st; struct _Node *pnext; nNode;int createlslink(char *path,int flag,nNode *head) DIR * dp; struct dirent *entry; struct stat statbuf; nNode *p; char abspath1024; if(dp=opendir(path)=NULL) fprintf(stderr,"cannot open directory:%sn",path); return -1; if(chdir(path) = -1) fprintf(stderr,"cannot cd directory:%sn",path); return -2; if(NULL=getcwd(abspath,1024) fprintf(stderr,"getcwd error!n"); return -3; while(entry=readdir(dp) != NULL) lstat(entry->d_name,&statbuf); if(!(flag & OPT_a) && (entry->d_name0='.') /*没有选项 -a 则不显示.开头的文件(或目录)名*/ continue; else p = (nNode *)malloc(sizeof(nNode); p->pnext = *head; *head = p; (*head)->length = strlen(entry->d_name); strcpy(*head)->path,abspath); strcpy(*head)->name,entry->d_name); memcpy(&(*head)->st),&statbuf,sizeof(struct stat); if(-1=chdir(".") fprintf(stderr,"cannot cd directory:.n"); return -3; if(closedir(dp) =-1) fprintf(stderr,"cannot close dpn"); return -4; return DONE_SUCCESS;void sortlslink(nNode *head,int flag) nNode *p,*q,r; int msuccess; if(!head) return; if(flag & OPT_f) else p = head; while(p->pnext) p = p->pnext; while(p!=head) q=head; msuccess = 1; while(q->pnext) if(strcmp(q->name,q->pnext->name)>0) memcpy(&r,q,sizeof(nNode); strcpy(q->name,q->pnext->name); strcpy(q->path,q->pnext->path); q->length = q->pnext->length; memcpy(&q->st,&(q->pnext->st),sizeof(q->st); strcpy(q->pnext->name,r.name); strcpy(q->pnext->path,r.path); q->pnext->length = r.length; memcpy(&(q->pnext->st),&(r.st),sizeof(r.st); msuccess = 0; if(q->pnext=p) break; q = q->pnext; if(msuccess) break; p = q;void format_long_print(nNode *head,int flag) nNode * p = head; char buf12; struct passwd *password; struct group *grp; struct tm * tm_ptr; char linkfilebuf1024; char pathfilename1024; char filename256; if(!p) return; while(p) if( !strcmp(p->name,".") | !strcmp(p->name,".") printf("%sn",p->name); else /*permission*/ strcpy(pathfilename,p->path); strcpy(filename,p->name); memset(buf,'-',11); buf11=0; if(S_ISDIR(p->st.st_mode) buf0 = 'd' else if(S_ISCHR(p->st.st_mode) buf0 = 'c' else if(S_ISBLK(p->st.st_mode) buf0 = 'b' else if(S_ISFIFO(p->st.st_mode) buf0 = 'p' else if(S_ISLNK(p->st.st_mode) buf0 = 'l' else if(S_ISSOCK(p->st.st_mode) buf0 = 's' if(S_IRUSR&p->st.st_mode) buf1 = 'r' if(S_IWUSR&p->st.st_mode) buf2 = 'w' if(S_IXUSR&p->st.st_mode) buf3 = 'x' if(S_IRGRP&p->st.st_mode) buf4 = 'r' if(S_IWGRP&p->st.st_mode) buf5 = 'w' if(S_IXGRP&p->st.st_mode) buf6 = 'x' if(S_IROTH&p->st.st_mode) buf7 = 'r' if(S_IWOTH&p->st.st_mode) buf8 = 'w' if(S_IXOTH&p->st.st_mode) buf9 = 'x' printf("%s ",buf); /*link number*/ printf("%4d ",p->st.st_nlink); /*owner*/ password = getpwuid(p->st.st_uid); if(password) printf("%s ",password->pw_name); else printf("%d ",p->st.st_uid); /* group */ grp= getgrgid(p->st.st_gid); if(grp) printf("%s ",grp->gr_name); else printf("%d ",p->st.st_gid); /*file bytes or dev number*/ if(S_ISBLK(p->st.st_mode) | S_ISCHR(p->st.st_mode) printf("%3u,",MAJOR(p->st.st_rdev); printf("%3u ",MINOR(p->st.st_rdev); else printf("%7u ",p->st.st_size); /*time*/ tm_ptr = localtime(&(p->st.st_mtime); printf("%02d-%02d ",tm_ptr->tm_mon+1,tm_ptr->tm_mday); printf("%02d:%02d ",tm_ptr->tm_hour,tm_ptr->tm_min); /*filename */ if(S_ISDIR(p->st.st_mode) printf("033;34m%s0330mn",filename); else printf("%s ",filename); if(S_ISLNK(p->st.st_mode) strcat(pathfilename,"/"); strcat(pathfilename,p->name); int rslt=readlink(pathfilename,linkfilebuf,1024); if (rslt<0) printf("readlink error!n"); exit(-1); linkfilebufrslt='0' printf("-> 033;32m%s0330m",linkfilebuf); printf("n"); p = p->pnext; return;void format_normal_print(nNode *head,int flag) nNode * p = head; while(p) if( ( (strcmp(p->name,".")=0) | (strcmp(p->name,".")=0) ) && (flag & OPT_a) printf("%sn",p->name); else if(S_ISDIR(p->st.st_mode) printf("033;32m%s0330mn",p->name); else printf("%sn",p->name); p = p->pnext; return;void showlslink(nNode *head,int flag) if(flag & OPT_l) format_long_print(head,flag); else format_normal_print(head,flag); return;void lspath(char *path,int flag) char pathname1024; char filename256; nNode *p = NULL; nNode *head = NULL; /*创建列文件链表 head*/ if (createlslink(path,flag,&head) != DONE_SUCCESS) printf("createlslink error!n"); return; /* 对链表排序 */ sortlslink(head,flag); /* 按选项显示链表内容 */ showlslink(head,flag); /*如果节点不是子目录,则删除节点,否则当有-R选项时,列子目录内容后删除节点 */ while(head) p = head; head = head->pnext; if(S_ISDIR(p->st.st_mode) && (flag & OPT_R) if( strcmp(p->name,".") && strcmp(p->name,".") ) strcpy(pathname,p->path); strcat(pathname,"/"); strcat(pathname,p->name); printf("033;32m%s:0330mn",pathname); lspath(pathname,flag); free(p); return;int main(int argc,char *argv) int opt; char path1024; int listflag = 0; struct stat statbuf; struct option longopts = "help",0,NULL,'h',"version",0,NULL,'v',0,0,0,0; while(opt=getopt_long(argc,argv,"afhlvR",longopts,NULL) != -1) switch(opt) case 'a': listflag |= OPT_a; break; case 'f': listflag |= OPT_f; break; case 'h': listflag |= OPT_h; break; case 'l': listflag |= OPT_l; break; case 'v': listflag |= OPT_v; break; case 'R': listflag |= OPT_R; break; case '?': printf("Usage:n %s -h n or n %s -help nfor helpn",argv0,argv0); exit(-1); if(listflag & OPT_h ) printf("Usage: %s -afhlvR directory1 directory2,.n",argv0); return 0; else if(listflag & OPT_v) printf("myls version 0.1nCopyright by YCG 2015n"); return 0; if(optind=argc) /* 列当前目录文件 */ if(NULL=getcwd(path,1024) return -1; lspath(path,listflag); else for(;optind<argc;optind+) if(lstat(argvoptind,&statbuf)<0) fprintf(stderr,"stat errorn"); return -1; if(S_ISDIR(statbuf.st_mode) lspath(argvoptind,listflag); else return 0;(3) 命令行运行: ./myls -l /home ./myls -l a /home ./myls -l a R ./myls -v ./myls -help ./myls -l /usr/bin /home /proc 认真阅读程序代码,参考代码并根据实验结果,完成实验总结。程序采用标识位的方式来判断命令选项,只要在对应二进制位为1,就认为该选项被键入,使用getopt_long来获取参数。对于目录文件,使用lspath函数列出文件与子目录,对于文件则不处理。在lspath函数里使用递归来实现子目录的访问,createlinks是将当前目录下的文件(包括目录文件)全部挂在头结点为head 的链,然后有lspath读取,若是目录文件则递归读取,直到非目录文件,使用format_normal_prin()(没有键入-l参数)或 format_long_prin()实现显示。整个程序设计原理很朴素,代码很简洁,只有递归稍微有点难理解。对于标识位存储命令参数信 息的做法感觉很实用,值得借鉴。4本实验程序完成了几个命令选项: -l: 以长型(列出含文件类型、权限、硬链接数、所有者名、组名、文件长度、最后修改时间和文件) -a: 隐含文件名也要列出 -R:子目录文件名也要列出 -v(-version):输出本软件(myls)版本号 -h(-help):输出本软件的版本信息 -f: 列文件名时,不排序(默认情况下列出的文件名是按名字排序的)本代码尚待完成的工作(1)对非长型格式输出,每行只列出了一个文件,通过修改程序,类似与LINUX命令ls,一行列出多个文件;在format_normal_prin()函数中修改 else printf("%s ",p->name); /不是目录文件/此处修改 p = p->pnext; printf("n");/此处修改 return;(2)对命令行参数,只能是目录 如上面 /home , /usr/bin , /proc, 以及默认的当前目录(.),对不是目录的情况,甚至含有通配符“*”和“?”的情况,请编写代码实现匹配和显示; if(S_ISDIR(statbuf.st_mode) lspath(argvoptind,listflag); else printf("为真正文件%s",argvoptind) ;/处理不是目录的情况对于含有通配符的情况,系统会自动对参数进行处理,不需要改进(写好了匹配代码在调试时发现)以下为调试截图(gdb) set args /home/chengchangf*/文档/L*(gdb) rStarting program: /home/chengchangfu/文档/Linux_document/实验6/myls /home/chengchangf*/文档/L*Breakpoint 1, main (argc=4, argv=0xbffff164) at myls.c:406406 lspath(argvoptind,listflag);(gdb) p argvoptind$1 = 0xbffff33d "/home/chengchangfu/文档/Linux*"(gdb) cContinuing.Breakpoint 1, main (argc=4, argv=0xbffff164) at myls.c:406406 lspath(argvoptind,listflag);(gdb) p argvoptind$2 = 0xbffff361 "/home/chengchangfu/文档/Linux_document"(gdb) cContinuing.asm_insert_test first helloworld helloworld.c second test 实验4 实验4_add 实验6 Breakpoint 1, main (argc=4, argv=0xbffff164) at myls.c:406406 lspath(argvoptind,listflag);(gdb) p argvoptind$3 = 0xbffff38a "/home/chengchangfu/文档/Linux实验"而我的文件夹正好是 Linux_document, Linux实验,Linux*,chengchangfulocalhost 文档$ lschapter03 copy_block.c Linux* Linux_document Linux实验 项目文件我没搞明白参数为什么会被自动处理,这样使得我自己写的处理函数无法发挥作用3)还可对比ls命令完善本程序,实现更多的命令行选项功能。