Linux c/c++下ls命令的实现(超详细)

今天我们要讨论的是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 <dirent.h>
struct dirent *readdir(DIR *dirp);

最多常见的readdir使用方式:

#include<stdio.h>
#include<dirent.h>
#include<string.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>

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: %s\n", 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<stdio.h>
#include<dirent.h>
#include<string.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>

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: %s\n", 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 <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>
#include <stdint.h>
#include <iostream>
#include <stdlib.h>

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);

		/* 如果使用 getpwuid() 找到所有者的名称,则打印出所有者的名称。  */
		if ((pwd = getpwuid(statbuf.st_uid)) != NULL)
		printf(" %-8.8s", pwd->pw_name);
		else
		printf(" %-8d", statbuf.st_uid);

		/* 如果使用 getgrgid() 找到组名,则打印出组名。 */
		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 %s\n", 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)

  • 12
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现类似于Linux下的ls -l命令可以使用C++的文件操作库和标准库函数实现。具体步骤如下: 1. 包含头文件 ```cpp #include <iostream> #include <fstream> #include <dirent.h> #include <sys/stat.h> #include <pwd.h> #include <grp.h> #include <time.h> ``` 2. 定义函数 ```cpp void listDir(const char* path); void printStat(struct stat st); void printFileType(mode_t mode); void printPermissions(mode_t mode); void printTime(time_t t); ``` 3. 实现函数 ```cpp void listDir(const char* path) { DIR* dir = opendir(path); if (dir == NULL) { std::cerr << "Failed to open directory " << path << std::endl; return; } dirent* entry; while ((entry = readdir(dir)) != NULL) { std::string filename(entry->d_name); if (filename == "." || filename == "..") { continue; } std::string filepath(path); filepath += "/"; filepath += filename; struct stat st; if (stat(filepath.c_str(), &st) != 0) { std::cerr << "Failed to get file stat: " << filepath << std::endl; continue; } printStat(st); std::cout << " " << filename << std::endl; } closedir(dir); } void printStat(struct stat st) { printFileType(st.st_mode); printPermissions(st.st_mode); std::cout << " " << st.st_nlink << " "; struct passwd* pw = getpwuid(st.st_uid); if (pw == NULL) { std::cerr << "Failed to get user name" << std::endl; return; } std::cout << pw->pw_name << " "; struct group* gr = getgrgid(st.st_gid); if (gr == NULL) { std::cerr << "Failed to get group name" << std::endl; return; } std::cout << gr->gr_name << " "; std::cout << st.st_size << " "; printTime(st.st_mtime); } void printFileType(mode_t mode) { if (S_ISREG(mode)) { std::cout << "-"; } else if (S_ISDIR(mode)) { std::cout << "d"; } else if (S_ISCHR(mode)) { std::cout << "c"; } else if (S_ISBLK(mode)) { std::cout << "b"; } else if (S_ISFIFO(mode)) { std::cout << "p"; } else if (S_ISLNK(mode)) { std::cout << "l"; } else if (S_ISSOCK(mode)) { std::cout << "s"; } } void printPermissions(mode_t mode) { std::cout << ((mode & S_IRUSR) ? "r" : "-"); std::cout << ((mode & S_IWUSR) ? "w" : "-"); std::cout << ((mode & S_IXUSR) ? "x" : "-"); std::cout << ((mode & S_IRGRP) ? "r" : "-"); std::cout << ((mode & S_IWGRP) ? "w" : "-"); std::cout << ((mode & S_IXGRP) ? "x" : "-"); std::cout << ((mode & S_IROTH) ? "r" : "-"); std::cout << ((mode & S_IWOTH) ? "w" : "-"); std::cout << ((mode & S_IXOTH) ? "x" : "-"); } void printTime(time_t t) { struct tm* tm = localtime(&t); char str[100]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", tm); std::cout << str; } ``` 4. 测试 ```cpp int main() { listDir("."); return 0; } ``` 这样就可以实现类似于Linux下的ls -l命令

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值