linux c编程实现ls -l递归调用子目录并缩进显示文件信息

linux c编程实现ls -l递归调用子目录并缩进显示文件信息

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<dirent.h>
#define N_BITS 3 //获取文件的权限设置的移位数
/*
输入参数:int类型的st_mode
返回值:字符型的文件类型标志
函数功能:通过传入的st_mode判断文件类型,返回字符型的文件类型标志
*/
char file_type(int mode){
	if(S_ISDIR(mode)){ //是否为目录
		return 'd';
	}
	if(S_ISREG(mode)){ //是否为普通文件
		return '-';
	}
	if(S_ISFIFO(mode)){ //是否为管道文件
		return 'p';
	}
	if(S_ISLNK(mode)){ //是否为符号链接文件
		return 'l';
	}
	if(S_ISBLK(mode)){ //是否为块文件
		return 'b';
	}
	if(S_ISSOCK(mode)){ //是否为套接字文件
		return 's';
	}
	if(S_ISCHR(mode)){//是否为字符文件
		return 'c';
	}
	return '0';
}
/*
输入参数:int类型的st_mode
返回值:整型 0表示成功 -1表示失败
函数功能:通过传入的st_mode获得user grop other三者的读写执行权限,同时按顺序打印出来,以rwx的方式显示
*/
int print_perm(int st_mode){
	int i;
	unsigned int mask = 0700; //匹配二进制
	static char *perm[] = {"---","--x","-w-","-wx","r--","r-x","rw-","rwx"};//文件权限的字符串数组
	//mask 与mode相与循环3次依次获得user grop other三者的权限,并打印输出到屏幕上
	for(i = 3; i; --i){
		printf("%3s",perm[(st_mode & mask) >> (i-1) * N_BITS]); //mode共有9bit,每3bit表示一个用户的读写和执行权限
		mask >>= N_BITS;
	}
	return 0;
}
/*
输入参数:stat的结构体,文件路径的指向字符串首地址的指针
返回值:整型 0:表示成功 1:表示失败
函数功能:打印文件名,并根据文件的类型显示相应的颜色
*/
int print_filename(struct stat file,char *filename) {
	char filename_ink[128] = {};
	memset(filename_ink,'\0',128); //将字符串填充'\0'
	if(S_ISDIR(file.st_mode)){ //目录显示蓝色
		printf("\033[34m%s\033[0m\n",filename);
		return 0;
	}
	if(S_ISLNK(file.st_mode)){ //符号链接显示天蓝色,同时打印出源文件
		readlink(filename,filename_ink,128); //readlink坏迷次募?存入到数组filename_ink中
		printf("\033[36m%s\033[0m -> %s\n",filename,filename_ink);//格式化打印符号链接文件
		return 0;
	}
	 if(S_IXUSR & file.st_mode || S_IXGRP & file.st_mode || S_IXOTH & file.st_mode){ //根据文件的三个用户有无执行权限,判断是否为可执行文件,如果是则打印绿色
		printf("\033[32m%s\033[0m\n",filename);	
		return 0;
	}
	printf("\033[30m%s\033[0m\n",filename); //普通文件打印黑色
	return 0;
}
/*
输入参数:stat的结构体类型,指向鬃址抵刚牖蛘咧赶蜃址椎刂返闹刚?,整型的递归深度
返回值:整型 1:表示成功 0:表示失败
函数功能:以ls -l 的方式打印出文件的各项内容,如下所示
文件类型 文件权限 硬链接数 用户名 组用户名 文件大小 月 日 最后修改时间mtime 文件名
  -      rwxrwxrwx 1        xxx    xxx        xx    11 4  20:22             lsfile 
*/
int list_file(struct stat file,char * filename,int deep){
	struct passwd *p_passwd; //passwd结构体内含有用户名属性
	struct group *p_group;//group结构体内含有组用户名属性
	struct tm *t; //tm结构体含有时间的基本信息

	t = localtime(&file.st_mtime); //通过localtime函数将st_mtime的整型秒数转化为tm类型
	
	p_passwd = getpwuid(file.st_uid); //获得passwd的结构体 
	p_group = getgrgid(file.st_gid);//获得group的结构体
		
	printf("%*s%c",deep,"",file_type(file.st_mode)); //根据递归深度打印文件信息,打印文件类型
	print_perm(file.st_mode);//打印文件权限
	printf("%5d%5s%8s%14d",file.st_nlink,p_passwd->pw_name,p_group->gr_name,file.st_size);//打印硬链接 用户名 组用户名 和文件大小
	printf("%3d%5d%3d:%2d ",t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min); //打印时间 月 日 时:分
	print_filename(file,filename);	 //打印文件名,显示颜色
	return 0;	
}
/*
输入参数:指向字符或者字符串首地址的指针 整型的递归深度
返回值:整型 0:表示成功 -1:表示失败
函数功能:访问目录下的文件,如果不是目录就打印文件信息,否则递归调用继续显示目录下的文件内容,即访问整个目录下的所有文件
*/
int list_dir(char *dirname,int deep){
	DIR *dirp;
	struct dirent *dir;
	struct stat file;
	if((dirp = opendir(dirname)) == NULL){ //读目录文件,返回空指针则读目录失败
		perror(dirname);
		exit(1);
	}
	chdir(dirname); //切换工作路径为当前目录
	while((dir = readdir(dirp)) != NULL){  //读目录里的文件内容,成功则返回dirent的结构体指针类型,直至读完结束
		if(lstat(dir->d_name,&file) != 0){ //lstat读文件属性,成功返回0
			perror(dir->d_name);
			continue;
		}
		if(S_ISDIR(file.st_mode)){ //判断是否为目录文件,如果是,则打印出目录文件信息,同时递归调用继续访问目录下的文件并打印出文件信息
			if(dir->d_name[0] == '.'){ //如果是. 或者 ..的隐藏文件则不显示,继续读下一个文件
				continue;
			}	
			list_file(file,dir->d_name,deep); 
			list_dir(dir->d_name,deep + 4); //递归调用
			chdir(".."); //切换工作路径为上一级工作目录
		}else {
			list_file(file,dir->d_name,deep); //不是目录则打印文件信息
		}
	}
	return 0;
}

int main(int argc, char *argv[]) {
	char path[1024] = {}; //保存用户输入的路径
	struct stat filePath; 
	if(argc < 2){ //参数小于2提示错误
		printf("loss argument\n");
		exit(1);
	}
	if((argc == 2  ) && !(strcmp(argv[1],"-l"))){ //参数为2且第二个参数为-l则显示当前目录的文件信息
		strcpy(path,"."); //复制路径
		list_dir(path,0); //调用目录显示函数,递归深度为0
		return 0;
	}
	if(argc == 3 && !strcmp(argv[1], "-l")){//如果参数为3个 且第二个参数为-l 则第三个参数为显示的文件路径
		if(lstat(argv[2],&filePath) == -1) { //是否能打开文件
			perror(argv[2]);
			exit(1);
		}
		if(S_ISDIR(filePath.st_mode)){ //如果是目录文件,则调用list_dir函数
			list_dir(argv[2],0);
		}else {
			list_file(filePath,argv[2],0); //否则打印文件内容,均以ls -l 的长格式方式打印
		}
		return 0;
	}else { //其余输入则输出错误信息
		printf("input error.\n");
		return 0;
	}
}

显示截图三个参数显示截图

猜你喜欢

转载自blog.csdn.net/qq_40832236/article/details/83720726
今日推荐