今天我们要讨论的是bash shell的一个重要命令,就是“ls”命令。Linux 中的 ls 命令是每个 Linux 用户都应该知道的最重要的命令之一。如果您是使用命令行的初学者,ls 可能是您应该尝试学习的第一个命令。
ls 是 list 的缩写,用于列出当前工作目录或其他目录(如果指定)中的文件。
ls命令为什么这么重要
ls 如此重要的原因在于它允许查看目录中的文件。将经常使用它来列出目录内容。 ls 不是一个复杂的命令,实现起来也很容易,但它确实包含许多不同的选项,可用于列出包含附加信息的文件。
在这过程中,你可能会发现其中一些选项非常有用,即使 ls 本身总是足以列出内容。掌握 ls 命令将使你更有效地列出目录内容和查找文件。它也可以在 Bash 脚本中使用,以帮助其他工具 *** 作文件。
最后,我们每天在使用linux的时候经常使用 ls 命令,但是你了解ls的实现吗?
快速了解ls命令
ls 命令列出目录中包含的文件和子目录。 您可以与 ls 一起使用的选项主要是为了列出附加信息,或者以不同的方式格式化输出。
ls -l显示文件或目录、大小、修改日期和时间、文件或文件夹名称和文件所有者及其权限。
其他选项这里就不列举出来了,感兴趣的可以通过man手册了解。
怎么实现ls命令?
我们已经通过在命令行上输入ls命令,列出目录中包含的文件和子目录。
-a 选项还将列出隐藏文件(名称以 . 开头的文件)。 除非您在根目录中,否则它还会列出 . (当前工作目录)和 … (向上一个目录)作为文件。
那么我们如何读取目录、文件信息呢?
#include
struct dirent *readdir(DIR *dirp);
最多常见的readdir使用方式:
#include#include #include #include #include #include using namespace std; #define FILE_NAME "/opt/code/linux_command_code" int main(int argc, char **argv) { DIR *dir; struct dirent *ptr; dir = opendir(FILE_NAME); if(NULL == dir) { cout << "opendir is NULL" << endl; return -1; } while( (ptr = readdir(dir))!=NULL) { printf("d_ino:%ld d_off:%ld d_name: %sn", ptr->d_ino,ptr->d_off,ptr->d_name); } closedir(dir); return 0; }
编译运行:
上面输出是未按照文件名排序。
readdir函数按照在磁盘的索引顺序,d_off来排序,若是须要按照文件名d_name,须要遍历后将文件名保存,再次排序。
- scandir 的使用
int scandir(const char *dir,struct dirent **namelist,int (*filter)(const void *b), int ( * compare )( const struct dirent **, const struct dirent ** ) ); int alphasort(const void *a, const void *b); int versionsort(const void *a, const void *b);
函数scandir扫描dir目录下以及dir子目录下满足filter过滤模式的文件,返回的结果是compare函数经过排序的,并保存在 namelist中。注意namelist是通过malloc动态分配内存的,所以在使用时要注意释放内存。alphasort和versionsort 是使用到的两种排序的函数。
常见scandir的使用:
#include#include #include #include #include #include using namespace std; #define FILE_NAME "/opt/code/linux_command_code" int main(int argc, char **argv) { struct dirent **namelist; int n; n = scandir(FILE_NAME,&namelist,0,alphasort); if(n < 0) { cout << "scandir return "<< n << endl; } else { int index=0; while(index < n) { printf("d_ino:%ld d_off:%ld d_name: %sn", namelist[index]->d_ino,namelist[index]->d_off,namelist[index]->d_name); free(namelist[index]); index++; } free(namelist); } return 0; }
编译运行:
scandir函数中能够直接调用排序函数,将遍历到的文件名按照顺序保存在队列中。
下面我们来看看怎么实现ls -l ;
如何实现 ls -l
在 Linux 中与 ls 命令一起使用的最常用选项之一是 -l。 此选项以更长的格式列出目录内容。
上面输出向我们显示目录中所有文件的文件权限、指向该文件的符号链接数量、每个文件的所有者和组、上次修改时间等。
下面是定义的7个字段。
char * getperm (char * , struct stat filestat); int getlinks(struct stat filestat); char * getuser (struct stat filestat); char * getgroup(struct stat filestat); int getsize (struct stat filestat); char * getdate (char * , struct stat filestat); char * getname (char * , char * , char , int);
获得文件信息
stat 能获取与文件系统及文件相关的许多信息,具体用途见stat的功能选项。这些信息包括inode、atime、ctime、mtime、文件(系统)类型、权限、块大小、符号连接等。
下面我来实现 ls -l,具体代码如下:
#include#include #include #include #include #include #include #include #include #include #include #include using namespace std; #define FILE_NAME "/opt/code/linux_command_code/ls/stat_test" char * getperm(char * perm , struct stat fileStat); int main(int argc , char * argv[]) { DIR *dir; struct dirent *dp; struct stat statbuf; struct passwd *pwd; struct group *grp; struct tm *tm; char datestring[256]; char modestr[11]; dir = opendir(FILE_NAME); if(NULL == dir) { cout << "opendir is NULL" << endl; return -1; } while ((dp = readdir(dir)) != NULL) { if (stat(dp->d_name, &statbuf) == -1) continue; printf("%10.10s", getperm(modestr,statbuf)); printf("%4d", statbuf.st_nlink); if ((pwd = getpwuid(statbuf.st_uid)) != NULL) printf(" %-8.8s", pwd->pw_name); else printf(" %-8d", statbuf.st_uid); if ((grp = getgrgid(statbuf.st_gid)) != NULL) printf(" %-8.8s", grp->gr_name); else printf(" %-8d", statbuf.st_gid); printf(" %9jd", (intmax_t)statbuf.st_size); tm = localtime(&statbuf.st_mtime); strftime(datestring, sizeof(datestring), nl_langinfo(D_T_FMT), tm); printf(" %s %sn", datestring, dp->d_name); } return 0; } char * getperm(char * perm , struct stat fileStat) { if ( S_ISLNK(fileStat.st_mode) ) { perm[0] = 'l'; } else if ( S_ISDIR(fileStat.st_mode) ) { perm[0] = 'd'; } else if ( S_ISCHR(fileStat.st_mode) ) { perm[0] = 'c'; } else if ( S_ISSOCK(fileStat.st_mode) ) { perm[0] = 's'; } else if ( S_ISFIFO(fileStat.st_mode) ) { perm[0] = 'p'; } else if ( S_ISBLK(fileStat.st_mode) ) { perm[0] = 'b'; } else { perm[0] = '-'; } perm[1] = ((fileStat.st_mode & S_IRUSR) ? 'r' : '-'); perm[2] = ((fileStat.st_mode & S_IWUSR) ? 'w' : '-'); perm[3] = ((fileStat.st_mode & S_IXUSR) ? 'x' : '-'); perm[4] = ((fileStat.st_mode & S_IRGRP) ? 'r' : '-'); perm[5] = ((fileStat.st_mode & S_IWGRP) ? 'w' : '-'); perm[6] = ((fileStat.st_mode & S_IXGRP) ? 'x' : '-'); perm[7] = ((fileStat.st_mode & S_IROTH) ? 'r' : '-'); perm[8] = ((fileStat.st_mode & S_IWOTH) ? 'w' : '-'); perm[9] = ((fileStat.st_mode & S_IXOTH) ? 'x' : '-'); if ( fileStat.st_mode & S_ISUID ) { perm[3] = 's'; } else if ( fileStat.st_mode & S_IXUSR ) { perm[3] = 'x'; } else { perm[3] = '-'; } if ( fileStat.st_mode & S_ISGID ) { perm[6] = 's'; } else if ( fileStat.st_mode & S_IXGRP ) { perm[6] = 'x'; } else { perm[6] = '-'; } if ( fileStat.st_mode & S_ISVTX ) { perm[9] = 't'; } else if ( fileStat.st_mode & S_IXOTH ) { perm[9] = 'x'; } else { perm[9] = '-'; } perm[10] = 0; return perm; }
编译运行:
- 权限
针对文件:r-查看,w-修改,x-执行
针对文件夹:r-列出文件夹下的所有文件和文件夹,w-在目录中创建和删除,x-进入目录
权限数字说明:权限字母组合转换为二进制1,0组合,有字母的位用1表示,-的位用0表示,然后转换为十进制数字。如:
rwx组合对应的二进制为 111,转换为十进制7
rw-组合对应的二进制为 110,转换为十进制6
r-x组合对应的二进制为 101,转换为十进制5
在struct stat中,文件所有者都是以ID形式存在的,代码中输出用户名和组名。主要使用了该函数:
char * getuser(struct stat fileStat) { struct passwd *pass = getpwuid(fileStat.st_uid); return pass->pw_name; } char * getgroup(struct stat fileStat) { struct group *pass = getgrgid(fileStat.st_gid); return pass->gr_name; }
总的来说,实现“ls -l”功能所涉及的特殊结构体较多,基础知识考察较多,需要注意细节。逻辑结构上算是很简单,没有什么需要特别留意的地方。
ls命令具体选项实现
使用 -t 选项按修改时间对文件进行排序。 这会将最近编辑的文件带到输出的顶部,使它们更容易找到。
使用 -R 选项递归列出目录的内容。 这意味着每个子目录的内容也将被列出。
int main(int argc , char * argv[]) { char c = 0; char ** arg = NULL; int count_arg = 0; options_t * opt = (options_t *) calloc(1 , sizeof(options_t)); while ( (c = getopt(argc, argv, "aSdltR")) != -1) { switch (c) { case 'a': opt->flag_a = 1; break; case 'S': opt->flag_S = 1; opt->flag_t = 0; break; case 'd': opt->flag_d = 1; break; case 'l': opt->flag_l = 1; break; case 't': opt->flag_t = 1; opt->flag_S = 0; break; case 'R': opt->flag_R = 1; break; case '?': break; default: printf ("?? getopt returned character code 0%o ??n", c); } } if (optind < argc) { arg = (char **) calloc ( (argc - optind) , sizeof(char *) ); count_arg = 0; while (optind < argc) { arg[count_arg++] = argv[optind++]; } } ls(opt , arg , count_arg); if( arg != NULL ) free( arg ); free(opt); return 0; }
编译运行
总结
在 Unix/Linux 的文件系统中,所有东西的储存形式都是文件(一切皆文件的理念)。ls命令是linux下最常用的命令之一,它的使用很简单,可是功能却很多,有很多的参数,本篇文章中给出了一些测试例子,方便理解ls命令。
欢迎关注微信公众号【程序猿编码】,需要ls命令源码的添加本人微信号(c17865354792)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)