unix/linux ls命令的实现
来源:互联网 发布:慢慢买数据怎么看 编辑:程序博客网 时间:2024/05/29 19:22
Understanding Unix/Linux Programming(Unix/Linux编程实践教程)
学习模式:
(1)它能做什么?
(2)它是如何实现的?
(3)能不能自己编写一个?
(实验环境:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) )
ls命令学习(1)ls命令能做什么
查看联机帮助:ls
可知ls默认列出当前目录的文件夹跟文件。按字典序排序。
ls还可以跟其他参数:ls -l
cong@ubantu:/$ ls -ltotal 100drwxr-xr-x 2 root root 4096 Mar 8 03:48 bindrwxr-xr-x 3 root root 4096 Mar 10 02:39 bootdrwxrwxr-x 2 root root 4096 Aug 22 2016 cdromdrwxr-xr-x 19 root root 4320 Mar 10 22:09 devdrwxr-xr-x 132 root root 12288 Mar 10 22:09 etcdrwxr-xr-x 3 root root 4096 Aug 22 2016 homelrwxrwxrwx 1 root root 32 Mar 8 03:56 initrd.img -> boot/initrd.img-4.4.0-66-genericlrwxrwxrwx 1 root root 32 Oct 24 23:51 initrd.img.old -> boot/initrd.img-4.4.0-45-genericdrwxr-xr-x 22 root root 4096 Aug 22 2016 libdrwxr-xr-x 2 root root 4096 Jul 19 2016 lib64drwx------ 2 root root 16384 Aug 22 2016 lost+founddrwxr-xr-x 4 root root 4096 Aug 22 2016 mediadrwxr-xr-x 3 root root 4096 Oct 15 04:39 mntdrwxr-xr-x 2 root root 4096 Jul 19 2016 optdr-xr-xr-x 223 root root 0 Mar 10 22:08 procdrwx------ 4 root root 4096 Oct 14 09:10 rootdrwxr-xr-x 27 root root 860 Mar 11 00:45 rundrwxr-xr-x 2 root root 12288 Mar 8 03:48 sbindrwxr-xr-x 2 root root 4096 Jun 29 2016 snapdrwxr-xr-x 2 root root 4096 Jul 19 2016 srvdr-xr-xr-x 13 root root 0 Mar 10 22:08 sysdrwxrwxrwt 12 root root 4096 Mar 11 00:45 tmpdrwxr-xr-x 11 root root 4096 Jul 19 2016 usrdrwxr-xr-x 14 root root 4096 Jul 19 2016 varlrwxrwxrwx 1 root root 29 Mar 8 03:56 vmlinuz -> boot/vmlinuz-4.4.0-66-genericlrwxrwxrwx 1 root root 29 Oct 24 23:51 vmlinuz.old -> boot/vmlinuz-4.4.0-45-generic
(2)ls是如何实现的?
目录是一种特殊的文件,目录是文件的列表。每个目录都至少包含两个特殊的项。“.”(当前目录),“..”(上一级目录)。
如何读取目录的信息?如何获取文件的信息?
man 3 readdir
struct dirent结构
man 3 opendir
有了上面的信息,我们很容易编写自己的ls命令。
(3)如何编写ls
#include<stdio.h>#include<dirent.h>#include<string.h>void show_ls(char filename[]);int main(int argc,char* argv[]){if(argc == 1)show_ls(".");while(--argc){printf("%s: \n",*++argv);show_ls(*argv);printf("\n");}return 0;}void show_ls(char filename[]){DIR* dir_ptr; //the directorystruct dirent* direntp; //each entryif((dir_ptr = opendir(filename)) == NULL)fprintf(stderr,"ls1: cannot open%s \n",filename);while((direntp = readdir(dir_ptr)) != NULL)printf("%-10s",direntp->d_name);closedir(dir_ptr);}
我们已经把当前目录文件的名称打印出来了。(默认打印“.”,"..",这完成可以通过程序过滤,字典序可以通过qsort)
接下来实现ls -l命令
ls -l命令需要文件的当前信息。
使用stat获得文件信息。
stat结构体
现在我们基本已经获得我们需要所有信息了,但是有些信息需要转换一下。才能跟shell标准下ls -l一致。
1.将模式串转为字符串。
在stat.h文件下可以看到很多关于模式判断的宏定义。这只是一部分, 可自行查阅。
#define S_IRUSR __S_IREAD /* Read by owner. */#define S_IWUSR __S_IWRITE /* Write by owner. */#define S_IXUSR __S_IEXEC /* Execute by owner. *//* Read, write, and execute by owner. */#define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC)#ifdef __USE_MISC# define S_IREAD S_IRUSR# define S_IWRITE S_IWUSR# define S_IEXEC S_IXUSR#endif#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. *//* Read, write, and execute by group. */#define S_IRWXG (S_IRWXU >> 3)#define S_IROTH (S_IRGRP >> 3) /* Read by others. */相关实现。
2.用用户ID/组ID转成字符串。
在struct stat中,文件所有者都是以ID形式存在的,然而ls要求输出用户名和组名。
(1)用户名: man 3 getpwuid
(2)组名: man 3 getgrgid
有了上面的信息之后,编码实现ls - l
#include<stdio.h>#include<sys/stat.h>#include<dirent.h>#include<sys/types.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<pwd.h>#include<grp.h>#include<time.h>void do_ls(char []);void do_stat(char* );void show_file_info(char* ,struct stat*);void mode_to_letters(int ,char[]);char* uid_to_name(uid_t);char* gid_to_name(gid_t);int main(int argc,char*argv[]){if(argc == 1)do_ls(".");else{while(--argc)printf("%s:\n",*++argv);do_ls(*argv);}return 0;}void do_ls(char dirname[]){/*list files in directory called dirname*/DIR* dir_ptr;struct dirent * direntp; /*each entry*/if((dir_ptr = opendir(dirname)) == NULL)perror("opendir fails");while((direntp = readdir(dir_ptr)) !=NULL)do_stat(direntp->d_name);closedir(dir_ptr);}void do_stat(char* filename){struct stat info;if((stat(filename,&info)) == -1)perror(filename);elseshow_file_info(filename,&info);}void show_file_info(char* filename,struct stat * info_p){/*display the info about filename . the info is stored in struct at * info_p*/char modestr[11];mode_to_letters(info_p->st_mode,modestr);printf("%s",modestr);printf("%4d ",(int)info_p->st_nlink);printf("%-8s ",uid_to_name(info_p->st_uid));printf("%-8s ",gid_to_name(info_p->st_gid));printf("%8ld ",(long)info_p->st_size);printf("%.12s ",ctime(&info_p->st_mtime)+4);printf("%s\n",filename);}void mode_to_letters(int mode,char str[]){strcpy(str,"----------");if(S_ISDIR(mode)) str[0] = 'd'; //"directory ?"if(S_ISCHR(mode)) str[0] = 'c'; //"char decices"?if(S_ISBLK(mode)) str[0] = 'b'; //block device?//3 bits for userif(mode&S_IRUSR) str[1] = 'r';if(mode&S_IWUSR) str[2] = 'w';if(mode&S_IXUSR) str[3] = 'x';//3 bits for groupif(mode&S_IRGRP) str[4] = 'r';if(mode&S_IWGRP) str[5] = 'w';if(mode&S_IXGRP) str[6] = 'x';//3 bits for otherif(mode&S_IROTH) str[7] = 'r';if(mode&S_IWOTH) str[8] = 'w';if(mode&S_IXOTH) str[9] = 'x';}char* uid_to_name(uid_t uid){struct passwd* pw_ptr;static char numstr[10];if((pw_ptr =getpwuid(uid)) == NULL){sprintf(numstr,"%d",uid);printf("world");return numstr;}return pw_ptr->pw_name;}char* gid_to_name(gid_t gid){/*returns pointer to group number gid, used getgrgid*/struct group* grp_ptr;static char numstr[10];if((grp_ptr =getgrgid(gid)) == NULL){printf("hello wofjl");sprintf(numstr,"%d",gid);return numstr;}elsereturn grp_ptr->gr_name;}运行结果:已经非常接近shell标准ls -l 命令
/** sol03.18.c ** ------------------------------------------------------------sol03.18.c is a versionof ls2.c that supports the -R option. This program alsosupports the suid, sgid, and sticky bit handling from solution3.12. ** ------------------------------------------------------------ * * ls2.c - supports -R option, * handles suid, sgid, sticky bits, also fixes bug, * *purpose list contents of directory or directories *action if no args, use . else list files in args *note uses lstat and pwd.h and grp.h *NOTE uses lstat to avoid chasing symlink loops * *build: cc sol03.18.c -o sol03.18 */#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<dirent.h>#include<sys/stat.h>void do_ls(char[],int);void dostat(char *,char *);void show_file_info( char *, struct stat *);void mode_to_letters( int , char [] );char *uid_to_name( uid_t );char *gid_to_name( gid_t );main(int ac, char *av[]){intR_flag = 0;intanyfiles = 0;while ( --ac ){if ( strcmp("-R", *++av) == 0 )R_flag = 1;else {do_ls( *av , R_flag );anyfiles = 1;}}if ( !anyfiles )do_ls(".", R_flag);}void do_ls( char dirname[] , int subdirs )/* *list files in directory called dirname *lists subdirs if `subdirs' is true *First: list contents of dirname, then * recurse to call each of the subdirs */{DIR*dir_ptr;/* the directory */struct dirent*direntp;/* each entry */char*fullpath;/* * get the problem case out of the way up front */if ( ( dir_ptr = opendir( dirname ) ) == NULL ){fprintf(stderr,"ls2: cannot open %s\n", dirname);return;}/* * ok, we can read the directory, make two passes through it */printf("%s:\n", dirname);fullpath = (char *)malloc(strlen(dirname) + 1 + MAXNAMLEN + 1);/* * pass 1: list the contents */while ( ( direntp = readdir( dir_ptr ) ) != NULL ){sprintf(fullpath,"%s/%s",dirname,direntp->d_name);dostat( fullpath, direntp->d_name );}/* * pass 2: rewind, traverse, and for each subdir, recurse */ /*The rewinddir() function resets the position of the directory stream dirp to the beginning of the directory*/if ( subdirs ){rewinddir(dir_ptr);while ( ( direntp = readdir( dir_ptr ) ) != NULL ){/* skip . and .. */if ( strcmp(".",direntp->d_name) == 0 || strcmp("..",direntp->d_name) == 0 )continue;sprintf(fullpath,"%s/%s",dirname,direntp->d_name);if ( isadir(fullpath) ){putchar('\n');do_ls( fullpath, subdirs );}}}/* all done with this dir, close up and go */closedir(dir_ptr);free(fullpath);}void dostat( char *fullpath, char *filename ){struct stat info;if ( lstat(fullpath, &info) == -1 )/* cannot stat */perror(filename);/* say why */else/* else show info */show_file_info(filename, &info);}void show_file_info( char *filename, struct stat *info_p )/* * display the info about 'filename'. The info is stored in struct at *info_p */{char*uid_to_name(), *ctime(), *gid_to_name(), *filemode();voidmode_to_letters(); char modestr[11];mode_to_letters( info_p->st_mode, modestr );printf( "%s" , modestr );printf( "%4d " , (int) info_p->st_nlink);printf( "%-8s " , uid_to_name(info_p->st_uid) );printf( "%-8s " , gid_to_name(info_p->st_gid) );printf( "%8ld " , (long)info_p->st_size);printf( "%.12s ", 4+ctime(&info_p->st_mtime));printf( "%s\n" , filename );}/* * utility functions *//* * This function takes a mode value and a char array * and puts into the char array the file type and the * nine letters that correspond to the bits in mode. * NOTE: It now codes suid, sgid, and sticky bits * see manual for details. */void mode_to_letters( int mode, char str[] ){ strcpy( str, "----------" ); /* default=no perms */ if ( S_ISDIR(mode) ) str[0] = 'd'; /* directory? */ if ( S_ISCHR(mode) ) str[0] = 'c'; /* char devices */ if ( S_ISBLK(mode) ) str[0] = 'b'; /* block device */ if ( mode & S_IRUSR ) str[1] = 'r'; /* 3 bits for user */ if ( mode & S_IWUSR ) str[2] = 'w'; if ( (mode & S_ISUID) && (mode & S_IXUSR) )str[3] = 's'; else if ( (mode & S_ISUID) && !(mode & S_IXUSR) )str[3] = 'S'; else if ( mode & S_IXUSR ) str[3] = 'x'; if ( mode & S_IRGRP ) str[4] = 'r'; /* 3 bits for group */ if ( mode & S_IWGRP ) str[5] = 'w'; if ( (mode & S_ISGID) && (mode & S_IXGRP) )str[6] = 's'; else if ( (mode & S_ISGID) && !(mode & S_IXGRP) )str[6] = 'S'; else if ( mode & S_IXGRP ) str[6] = 'x'; if ( mode & S_IROTH ) str[7] = 'r'; /* 3 bits for other */ if ( mode & S_IWOTH ) str[8] = 'w'; if ( (mode & S_ISVTX) && (mode & S_IXOTH) )str[9] = 't'; else if ( (mode & S_ISVTX) && !(mode & S_IXOTH) )str[9] = 'T'; else if ( mode & S_IXOTH ) str[9] = 'x';}#include<pwd.h>char *uid_to_name( uid_t uid )/* *returns pointer to username associated with uid, uses getpw() */{structpasswd *getpwuid(), *pw_ptr;static char numstr[10];if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){sprintf(numstr,"%d", uid);return numstr;}elsereturn pw_ptr->pw_name ;}#include<grp.h>char *gid_to_name( gid_t gid )/* *returns pointer to group number gid. used getgrgid(3) */{struct group *getgrgid(), *grp_ptr;static char numstr[10];if ( ( grp_ptr = getgrgid(gid) ) == NULL ){sprintf(numstr,"%d", gid);return numstr;}elsereturn grp_ptr->gr_name;}/* * boolean: tells if arg names a directory */isadir(char *str){struct stat info;return ( lstat(str,&info) != -1 && S_ISDIR(info.st_mode) );}
0 0
- unix/linux ls命令的实现
- Unix - ls命令的简要实现
- unix ls命令的一个简单实现
- UVA400-Unix的ls命令
- linux ls命令实现
- linux命令实现:ls
- Linux ls命令实现
- Linux命令的实现 -- ls pwd cd
- linux编程:ls命令的简单实现
- Linux下ls命令的实现
- Linux下ls命令的简单实现
- Linux ls -l命令的实现
- 实现Linux下的ls命令
- 实现linux下的ls命令
- <<探讨linux/unix>>之命令ls
- unix/linux编程实践教程:ls命令
- ls命令的实现
- ls 命令的实现
- 【洛谷 1355】神秘大三角
- poj 1308 判断是否为一棵树
- groovy优势:自定义动态Bean
- Jquery实现Ajax应用
- #UWP#导航(navigation)的实现
- unix/linux ls命令的实现
- JZOJ 3637. 【COCI2013】linije
- Eclipse JSP/Servlet 环境搭建
- python系列整理列表
- 高精度板( 无除法、减法 )
- non-random numbers
- 使用HTML标签
- ArcGIS面简化工具的BUG
- 欧氏距离和余弦相似度