如果我们已经对my_ls.c的结构有了深刻了解,以及对此程序中所涉及系统调用函数都已理解,那么不妨继续增添选选型,让你的ls命令程序不断完整。正如你所理解的那样,前面我们实现的my_ls.c属于一个“插座”,要实现其他选项,基本上都是在my_ls.c源码中添加新代码。我们将不断完善选项功能的那个源码称为my_ls_plus.c。
1.增加-i选项
ls -i可以显示出每个文件的i节点编号。具体的实现办法是利用stat族函数,将文件的属性返回到类型为struct stat的参数buf中,然后在需要的位置打印st_ino字段即可。注意st_ino打印的时候需要长整型。
获取文件属性举例:
if(lstat(pathname,&buf)==-1) { my_err("lstat",errno,__LINE__); }
打印举例:
if(if_i) { printf("%ld ",buf.st_ino); }
2.增加-t选项
ls -t 按每个文件最后一次被修改的时间(st_mtime)排列显示文件。这里对文件属性中三个关于时间的字段做以说明。
st_atime:文件最后一次被访问(access)的时间。这个好理解。
st_mtime:文件最后一次被修改(modification)的时间。
st_ctime:文件字后一次被更改(create)的时间。
mtime和ctime其实都是修改时间,但是前者指文件内容被修改后的时间,而后者更倾向于文件所有者、所属组以及文件权限等属性被更改后的时间。当然如果文件内容修改,两者的时间都会被修改。我们一般用ls -l所显示的时间指mtime,而要显示出ctime则可以用: ls -lc。显示出atime则可以用:ls -lu。
因此,要实现ls -t命令的作用,我们必须对文件按照mtime进行排序。我们可以设置全局变量if_t来标记是否出现了 -t选项。如果出现则调用按照时间排序的函数sort_by_mtime(char filename[][PATH_MAX+1],int count);此函数的大致流程是:首先利用stat族函数获取每个文件的mtime,存于字符串数组mtime[256][20]中;再利用某种排序算法排序即可。如果你对C语言基本知识掌握的还算可以,那么要实现上述过程并不困难。
获取文件的mtime示例代码如下:(由于代码插件问题,请忽略<后面的‘\’)
for(i=0;i<\count;i++) { if(stat(filename[i],&buf)==-1) { my_err("stat",errno,__LINE__); } strcpy(buf_time,ctime(&buf.st_mtime)); buf_time[strlen(buf_time)-1]='\0'; convert_time(mtime[i],buf_time); }
下面的排序代码采用选择排序法进行排序,注意我们在比较的时候必然是对时间进行比较,而在交换两个数据的时候,必须对文件名和时间一起交换。当初我只交换了文件名,找了好久的”错误”。
//sorting for(i=0;i<\count;i++) { k=i; for(j=i;j<\count;j++) { if(strcmp(mtime[j],mtime[k])>\0) k=j; } if(k!=i) { //exchange mtime strcpy(temp,mtime[i]); strcpy(mtime[i],mtime[k]); strcpy(mtime[k],temp); //exchange filename strcpy(temp,filename[i]); strcpy(filename[i],filename[k]); strcpy(filename[k],temp); } }
这样,你就可以实现-t选项的功能。
3.增加-A选项
这个选项理解比较简单。我们知道ls -a是显示包括隐藏文件在内的所有文件。而ls -A则显示除了.和..之外的所有文件。我们知道在my_ls.c中void display(int flag,char* pathname)是根据flag对单个文件pathname进行处理,根据flag的情况来判断是以什么方式显示所有文件名。因为我们可以在此基础上加入对-A选项的判断:
if((if_A&&!strcmp(pathname,"."))||(if_A&&!strcmp(pathname,".."))) { //blank sentence,do not list this file } else { //省略switch语句 }
这样就可以实现-A选项了。
4.增加-B选项
如果你完成了-A选项,那么此选项对你来说轻而易举。-B选项是不显示以~结尾的备份文件。那么只要在-A选项的基础上修改源代码,示例如下:
if((if_A&&!strcmp(pathname,"."))||(if_A&&!strcmp(pathname,".."))) { //blank sentence,do not list this file } else if(if_B&&pathname[strlen(pathname)-1]=='~') { //blank sentence,do not list this file } else { //switch语句省略 }
5.增加-d选项
-d选项只会显示当前目录(.),而不是目录下的文件。如果加入-l则会显示当前目录的各种属性。前面的-B等选项我们在添加的时候都是在display函数中添加某些代码,因为最终结果还要与-a和-l选项相结合。比如ls -laA,虽然不显示.和..,但是还是要显示以.开始的其他文件。而-d选项则不用看-a的“脸色‘。因为不论你是否加入-a选项,此选项只会显示当前目录。如下:
edsionte@edsionte-laptop:~/code/file$ ls -laAd drwxr-xr-x 2 edsionte edsionte 4096 2010-07-06 14:50 . edsionte@edsionte-laptop:~/code/file$ ls -ld drwxr-xr-x 2 edsionte edsionte 4096 2010-07-06 14:50 . edsionte@edsionte-laptop:~/code/file$ ls -d .
因此关于此选项的代码应添加在display_dir函数中,具体位置如下:
//if the command include '-d' if(if_d) { if(stat(".",&buf)<\0) { my_err("stat",errno,__LINE__); } if(flag_param==PARAM_L||flag_param==PARAM_L+PARAM+A) display_attribute(buf,"."); else display_single(buf,"."); } else { for(i=0;i<\count;i++) { display(flag_param,filename[i]); } }
这样添加即可,通过以上几个选项的添加,你应该大致了解应该在何处添加代码了。
待续。。