Linux实验之仿ls命令

仿写ls -l的功能(编写myls程序),参数通过命令行传入:
1、获取当前工作目录路径并对该目录实现遍历
2、仿ls -l以列表形式出当前工作目录下的所有文件(包括子目录)
需显示的文件属性有:
文件类型 权限 硬链接数 所有者用户名 所有者所在组用户名 文件大小 最后修改时间
文件属性
1.获取当前工作路径
头文件:unistd.h
函数:*char get_current_dir_name();
成功返回路径字符串缓冲区指针(该内存区需要手动释放),
失败返回NULL

2.打开关闭目录函数
头文件:dirent.h
函数:DIR * opendir(const char * name);
打开name指定的目录,并关联一个目录流(类似于C库函数中的文件流),失败返回NULL
函数:int closedir(DIR *dir);
关闭指定目录流,释放相关数据结构。成功返回0;失败返回-1

3.读取目录文件函数
头文件:sys/types.h; dirent.h
函数:*struct dirent * readdir(DIR dir);
读取目录流dir标识的目录下文件,到达文件结尾或者错误发生,返回NULL

4.获取文件信息
头文件:sys/stat.h
函数:
*int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat buf);
读取path参数指定文件的文件属性,填充到buf参数指向的结
构体。lstat返回符号链接(快捷方式)的文件属性,stat返回符号链接引用文件(源头文件)的文件属性

5.1 获取用户属性函数
头文件:sys/types.h;pwd.h
函数:*struct passwd getpwuid(uid_t uid);
输入用户ID,返回用户属性信息(passwd结构)

5.2 获取用户组属性函数
头文件:sys/types.h;grp.h
函数:*struct group getgrgid(gid_t gid);
输入用户组ID,返回用户组属性信息(group结构)

6.获取文件时间信息
头文件:time.h
函数:char ctime(const time_t timep);
ctime直接解析为当地时间格式例如“wed jun 30 21:49:08 1993\n”

源程序:

#include<unistd.h>
#include<dirent.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pwd.h>
#include<grp.h>
#include<iostream>
using namespace std;

void print_type(mode_t st_mode);//判断并输出文件类型
void print_perm(mode_t st_mode);//判断并输出文件权限
void print_link(nlink_t st_nlink);//输出文件硬链接数
void print_usr_name(uid_t st_uid);//输出文件所有者
void print_group_name(gid_t st_gid);//输出用户组名
void print_file_size(off_t st_size);//输出文件大小
void print_time(time_t st_time);//输出最后一次修改时间
void print_file_name(char *file_name);//输出文件名

int main(int argc, char *argv[]){
	/*
	if(argc != 3){
		printf("argc=%d\t命令错误,请重试!!\n",argc);
		return -1;
	}
	printf("test1:\t参数1:%s\t参数2:%s\n",argv[1],argv[2]);
	if(strcmp(argv[2],"-l"|"-s") == 0){
		printf("true,-l\n");
	}
	*/

	/*
	for(int i = 0; i < argc; i++ ){
		printf("argv[%d]=%s\n",i,argv[i]);
	}*/
	
	/*
	--help	解释文档
	-l		l,即List,列表。		展示文件详细信息
	-c		c,即Catalog,目录。	展示目录本身“.”和上级目录“..”
	-a		a,即All,全部。		展示隐藏文件(以.开头)
	-p		p,即Property,属性		展示符号链接的文件属性 ,默认是返回符号链接引用文件的文件属性
	*/
	
	int ls_flag, help_flag, l_flag, c_flag, a_flag, p_flag;
	ls_flag = help_flag = l_flag = c_flag = a_flag = p_flag = 0;
	
	if(strcmp(argv[1],"ls") == 0){//主命令
		ls_flag = 1;
	}
	for(int i = 2; i < argc; i++ ){
		if(strcmp(argv[i],"--help") == 0){
			help_flag = 1;
		}
		if(strcmp(argv[i],"-l") == 0){
			l_flag = 1;
		}
		if(strcmp(argv[i],"-c") == 0){
			c_flag = 1;
		}
		if(strcmp(argv[i],"-a") == 0){
			a_flag = 1;
		}
		if(strcmp(argv[i],"-p") == 0){
			p_flag = 1;
		}
	}
	//printf("test12:\t参数判断:ls_flag=%d help_flag=%d l_flag=%d c_flag=%d a_flag=%d p_flag=%d\n",ls_flag,help_flag,l_flag,c_flag,a_flag,p_flag);

	//①ls --help
	if(help_flag == 1 && argc == 3){
		cout<<"myls程序帮助文档:"<<endl;
		cout<<"-l\tl,即List,列表。\t展示文件详细信息"<<endl;
		cout<<"-c\tc,即Catalog,目录。\t展示目录本身“.”和上级目录“..”"<<endl;
		cout<<"-a\ta,即All,全部。\t展示隐藏文件(以.开头)"<<endl;
		cout<<"-p\tp,即Property,属性\t展示符号链接引用文件的文件属性,默认是返回符号链接的文件属性"<<endl;
		exit(0);
	}
	/*
	else{//ls --help之后存在参数,报错
		printf("命令错误,正确帮助命令为:ls --help\n");
		exit(-1);
	}*/
	
	//获取当前工作目录
	char * current_dir_name = NULL;
	current_dir_name = get_current_dir_name();
	//printf("test2:\t当前目录:%s\n",current_dir_name);
	
	//打开当前工作目录
	DIR * current_dir = NULL;//目录文件类型
	struct dirent * current_dp = NULL;//
	struct stat  current_stat;//获取文件信息
	if((current_dir = opendir(current_dir_name)) == NULL){
		printf("打开目录失败,请重试\n");
		return -1;
	}
	else{
		//printf("目录下包含的文件是:\n");
		while((current_dp = readdir(current_dir)) != NULL){
			if(ls_flag == 1){//ls主命令存在
				if(argc == 2){//仅仅是命令ls
					//②ls
					if(current_dp->d_name[0] != '.'){//排除一二级目录文件和隐藏文件
						printf("%s\t",current_dp->d_name);
					}
				}
				else{//除命令ls外,其后还有其他参数
					if(l_flag == 0 && c_flag == 1 && a_flag == 0){//ls -c
						if(current_dp->d_name[0] != '.' || strcmp(current_dp->d_name,".") == 0 || strcmp(current_dp->d_name,"..") == 0){
							printf("%s\t",current_dp->d_name);
						}
					}
					else if(l_flag == 0 && a_flag == 1){//ls -a (-c/-p)
							printf("%s\t",current_dp->d_name);
					}
					else if(l_flag == 0){//ls -p
						if(current_dp->d_name[0] != '.'){//排除一二级目录文件和隐藏文件
							printf("%s\t",current_dp->d_name);
						}
					}
					else if(l_flag == 1 && c_flag == 0 && a_flag == 0){//*******③ls -l (-p)
						//printf("test3:\t文件名:%s\n",current_dp->d_name);
						if(current_dp->d_name[0] != '.'){//排除一二级目录文件和隐藏文件
							//if((stat(current_dp->d_name,&current_stat)) == -1 ){
							if((p_flag == 1)?((stat(current_dp->d_name,&current_stat)) == -1):((lstat(current_dp->d_name,&current_stat)) == -1)){
								//判断p_flag是否为1,若为1则使用stat函数
								printf("获取文件(%s)详细信息失败\n",current_dp->d_name);
								continue;
							}
							else{
								print_type(current_stat.st_mode);
								print_perm(current_stat.st_mode);
								print_link(current_stat.st_nlink);
								print_usr_name(current_stat.st_uid);
								print_group_name(current_stat.st_gid);
								print_file_size(current_stat.st_size);
								print_time(current_stat.st_mtime);
								print_file_name(current_dp->d_name);
							}
						}
					}
					else if(l_flag == 1 && c_flag == 1 && a_flag == 0){//*******④ls -l -c  (-p)
						if(current_dp->d_name[0] != '.' || strcmp(current_dp->d_name,".") == 0 || strcmp(current_dp->d_name,"..") == 0){//包括当前目录“.”和上级目录“..”,排除其他.隐藏文件
							//if((stat(current_dp->d_name,&current_stat)) == -1 ){
							if((p_flag == 1)?((stat(current_dp->d_name,&current_stat)) == -1):((lstat(current_dp->d_name,&current_stat)) == -1)){
								//判断p_flag是否为1,若为1则使用stat函数
								printf("获取文件(%s)详细信息失败\n",current_dp->d_name);
								continue;
							}
							else{
								print_type(current_stat.st_mode);
								print_perm(current_stat.st_mode);
								print_link(current_stat.st_nlink);
								print_usr_name(current_stat.st_uid);
								print_group_name(current_stat.st_gid);
								print_file_size(current_stat.st_size);
								print_time(current_stat.st_mtime);
								print_file_name(current_dp->d_name);
							}
						}
					}
					else if(l_flag == 1 && a_flag == 1){
						
						//包括当前目录“.”和上级目录“..”,排除其他.隐藏文件
							//if((stat(current_dp->d_name,&current_stat)) == -1 ){
							if((p_flag == 1)?((stat(current_dp->d_name,&current_stat)) == -1):((lstat(current_dp->d_name,&current_stat)) == -1)){
								//判断p_flag是否为1,若为1则使用stat函数
								printf("获取文件(%s)详细信息失败\n",current_dp->d_name);
								continue;
							}
							else{
								print_type(current_stat.st_mode);
								print_perm(current_stat.st_mode);
								print_link(current_stat.st_nlink);
								print_usr_name(current_stat.st_uid);
								print_group_name(current_stat.st_gid);
								print_file_size(current_stat.st_size);
								print_time(current_stat.st_mtime);
								print_file_name(current_dp->d_name);
							}
						
					}
					
					
				}
			}
			else{//ls不存在,报错
				printf("命令错误,请重试\n");
				exit(-1);
			}
			
		}
		if(l_flag == 0){
			cout<<endl;//回车更美观
		}
		closedir(current_dir);
	}
	
	free(current_dir_name);//手动释放缓存
	return 0;
}

void print_type(mode_t st_mode){
	char * ptr = NULL;
	if(S_ISREG(st_mode))			ptr = "-";//- 普通文件
	else if(S_ISDIR(st_mode))	ptr = "d";//d 目录文件
	else if(S_ISCHR(st_mode))	ptr = "c";//c 字符设备文件
	else if(S_ISBLK(st_mode))	ptr = "b";//b 块设备文件
	else if(S_ISFIFO(st_mode))	ptr = "p";//p 管道或FIFO
	else if(S_ISLNK(st_mode))	ptr = "l";//l 符号链接
	else if(S_ISSOCK(st_mode))	ptr = "s";//s 套接字
	else ptr = " ";
	//printf("test4:\t文件类型=%s\n",ptr);
	printf("%s",ptr);
}

void print_perm(mode_t st_mode){//r读 w写 x执行
	char ptr[10];
	//判断文件所有者权限
	if((S_IRUSR&st_mode) == S_IRUSR)	strcat(ptr,"r");
	else					strcat(ptr,"-");
	if((S_IWUSR&st_mode) == S_IWUSR)	strcat(ptr,"w");
	else					strcat(ptr,"-");
	if((S_IXUSR&st_mode) == S_IXUSR)	strcat(ptr,"x");
	else					strcat(ptr,"-");
	//判断用户组权限
	if((S_IRGRP&st_mode) == S_IRGRP)	strcat(ptr,"r");
	else					strcat(ptr,"-");
	if((S_IWGRP&st_mode) == S_IWGRP)	strcat(ptr,"w");
	else					strcat(ptr,"-");
	if((S_IXGRP&st_mode) == S_IXGRP)	strcat(ptr,"x");
	else					strcat(ptr,"-");
	//判断其他用户权限
	if((S_IROTH&st_mode) == S_IROTH)	strcat(ptr,"r");
	else					strcat(ptr,"-");
	if((S_IWOTH&st_mode) == S_IWOTH)	strcat(ptr,"w");
	else					strcat(ptr,"-");
	if((S_IXOTH&st_mode) == S_IXOTH)	strcat(ptr,"x");
	else					strcat(ptr,"-");

	//printf("test5:\t文件权限=%s\n",ptr);
	printf("%s",ptr);
}

void print_link(nlink_t st_nlink){
	//printf("test6:\t硬链接数=%d\n",st_nlink);
	printf(" %d",st_nlink);
}

void print_usr_name(uid_t st_uid){
	struct passwd *current_passwd = NULL;//passwd结构
	current_passwd = getpwuid(st_uid);
	//printf("test7:\t文件所有者=%s\n",current_passwd->pw_name);
	printf("\t%s",current_passwd->pw_name);
}

void print_group_name(gid_t st_gid){
	struct group *current_group = NULL;//group结构
	current_group = getgrgid(st_gid);
	//printf("test8:\t用户组=%s\n",current_group->gr_name);
	printf("\t%s",current_group->gr_name);
}

void print_file_size(off_t st_size){
	//printf("test9:\t文件大小=%ld\n",st_size);
	printf("\t%ld",st_size);
}

void print_time(time_t st_time){
	struct tm *current_tm = NULL;
	current_tm= localtime(&st_time);
	//printf("test10:\t最后一次修改时间=%d-%d-%d %d:%d:%d\n",current_tm->tm_year+1900, current_tm->tm_mon+1, current_tm->tm_mday, current_tm->tm_hour, current_tm->tm_min, current_tm->tm_sec);
	printf("\t%d-%d-%d %d:%d:%d",current_tm->tm_year+1900, current_tm->tm_mon+1, current_tm->tm_mday, current_tm->tm_hour, current_tm->tm_min, current_tm->tm_sec);
}

void print_file_name(char *file_name){
	//printf("test11:\t文件大小=%s\n",file_name);
	printf("  \t%s\n",file_name);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值