linux_shell之ls部分功能实现

主要实现以下功能:

ls:显示当前目录下的所有文件(不含隐藏文件)

ls -a:显示当前目录下的所有文件(含隐藏文件)

ls -l:显示当前目录下的所有文件的详细信息

ls -R:显示当前目录下的文件及其子目录下的所有文件

 

 

通过实现代码相应的总结:

1.考虑各个选项对结果的控制,考虑将文件信息保存在一个全局数组当中,这样,可以根据后面各个选项的要求进行对格式信息的调整,可以通过控制这个信息数组,可以实现绝大多数选项功能,但是在进行-R选项功能的时候出现了问题,所以在本次实现中,其他的3个选项是基于同一个查询,-R则另外根据了一个查询,这里日后如果有其他好的方法可以改下,目前暂时没有什么思路。

2.关于选项的控制,这里呢,是用一个数组来保存相应的选项开关的,如果命令中出现该选项,则对应项为1,反之,对应项为0,这样在后面检测的时候就可以根据相应的位置是否为1来进行相应的分流操作,这样的好处是不需要进行硬性的字符串比较,真正的ls也肯定不是进行字符串比较的,这里是仿ls进行的操作。不论选项如果排列,是分开还是合在一起,抑或重复出现,都是可以进行处理的。

3.原先以为ls -R使用了栈结构来遍历文件目录,后来发现还是用的递归遍历数组,这样的话,在很大程度上现在的实现已经基本符合了,现在唯一要考虑的就是信息该如何保存并显示,是该存在一个全局变量中,还是一个局部变量中,是查到一项就输出,还是全部查好之后在输出,这都是可以考虑的地方。

4.这里也没有考虑文件名长度是否能够容纳的问题,而是分配的一个数组来存储相应的文件名字的,后续可以考虑结合动态内存分配。


附上代码:

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <time.h>

#define MAX_COUNT 100 //总共能够统计的文件项数,用这个值去分配保存信息的数组的大小
#define FILE_LENGTH_MAX 20 // 自定义的一个文件的最长长度。

enum EOPT
{ 
	E,E_a,E_l,E_r,E_num	
}; // 相应的控制选项,E为ls,E_a为ls -a,E_r为ls -R,E_l为ls -l
int getOPT[E_num] = {0}; // 一个保存相应选项的状态数组

typedef struct
{
	mode_t	st_mode;
	uid_t	st_uid;
	gid_t	st_gid;
	off_t	st_size;
	nlink_t	st_nlink;
	char*	fname;
	struct timespec	st_time;

}fileInfo; // 由于很多信息在这里没用,所以自定义了一个文件项信息结构
static fileInfo* fInfo; // 所有的函数通过这个指针对查询结果进行操作
static int fileCount; // 统计目前已经统计了多少个文件项

int query(char*); // 普通查询,将结果存于fInfo数组中
int query_r(char*); // 递归遍历查询
int isHideFile(const char*); // 判断是否是隐藏文件
void print(); // 没有-l选项的打印
void printl();  // 附加-l选项
void printInfo(const fileInfo);
int getmode(const char*); // 获取相应选项信息
void rprintl(const char*,struct stat); // 递归遍历中的附加-l选项打印
void rprint(const char*); // 递归遍历中的普通打印
int main(int argc,char *argv[])
{
	char buf[1024]; // 用来保存文件名
	//getcwd(buf,1024);
	if(argv[argc-1][0] == '-' || argc == 1)
		getcwd(buf,1024);
	else
		strcpy(buf,argv[argc-1]);
	int i = 1;
	for(;i<argc;i++)
		getmode(argv[i]);
	if(getOPT[E_l]!=1) // 如果没有指定-l,默认就是不打印文件的详细信息
		getOPT[E] = 1;
	if(getOPT[E_r] == 0){
		query(buf);
		if(getOPT[E_l] == 1)
			printl();
		else
			print();
	}
	else
		query_r(buf);
	return EXIT_SUCCESS;
}
int getmode(const char* arg) // 将相应的选项变为1
{
	if(arg[0]!='-')
		return -1;
	const char *p;
	p = &arg[1];
	while(*p!=0)
	{
		if(*p == 'a')
			getOPT[E_a] = 1;
		else if(*p == 'l')
			getOPT[E_l] = 1;
		else if(*p == 'R')
			getOPT[E_r] = 1;
		p++;
	}
	return 0;
}
int query(char* pathname)
{
	fInfo = (fileInfo*)malloc(sizeof(fileInfo)*MAX_COUNT);
	if(fInfo == NULL)
	{
		printf("fInfo allocate error\n");
		return -1;
	}
	struct dirent *dirp;
	DIR *dp;
	struct stat bufstat;
	fileInfo *tmp = fInfo;
	if((dp = opendir(pathname)) == NULL)
	{
		printf("opendir error\n");
		return -1;
	}
	while((dirp = readdir(dp))!=NULL)
	{
		fileCount++;
		strcpy(&pathname[n],dirp->d_name);
		if(lstat(pathname,&bufstat) < 0)
		{
			printf("lstat error\n");
			return -1;
		}
		tmp->fname = (char*)malloc(sizeof(char)*(strlen(dirp->d_name)+1));
		strcpy(tmp->fname,dirp->d_name);
		tmp->st_mode = bufstat.st_mode;
		tmp->st_uid = bufstat.st_uid;
		tmp->st_gid = bufstat.st_gid;
		tmp->st_size = bufstat.st_size;
		tmp->st_nlink = bufstat.st_nlink;
		tmp->st_time = bufstat.st_ctim;
		tmp++;
	}
	pathname[n-1] = 0;
	closedir(dp);
	return 0;
}
int isHideFile(const char*pathname)
{
	if(pathname[0] == '.')
		return 1;
	else
		return 0;
}
void print() 
{
	int i = 0;
	for(;i<fileCount;i++){
		if(getOPT[E_a] == 0 && isHideFile(fInfo[i].fname)) // 如果没有指定-a选项,并且当前文件为隐藏文件,则跳过
				continue;
			printf("%s\n",fInfo[i].fname);
	}
}
void printl()
{
	int i = 0;
	for(;i<fileCount;i++)
	{
		if(getOPT[E_a] == 0 && isHideFile(fInfo[i].fname))
			continue;
		printInfo(fInfo[i]);
		printf("\n");
	}
}
void printInfo(const fileInfo file) // 打印详细的信息,这里是仿windows下的信息显示
{
	struct tm *p;
	p = gmtime(&(file.st_time.tv_sec));
	printf("%d/%d/%d\t%d:%d:%d\t",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
	if(S_ISDIR(file.st_mode))
		printf("\t<DIR>\t\t");
	else
		printf("\t\t\t");
	printf("%s",file.fname);	
}

int query_r(char* pathname)
{
	struct dirent *dirp;
	DIR * dp;
	struct stat bufstat;
	if((lstat(pathname,&bufstat)) < 0)
	{
		printf("lstat error\n");
		return -1;
	}
	if(S_ISDIR(bufstat.st_mode) == 0) {// 对普通文件进行处理		
		if(getOPT[E_l] == 1)
			rprintl(pathname,bufstat);
		else
			rprint(pathname);
		return 0;	
	}
	int n = strlen(pathname);
	pathname[n++] = '/';
	pathname[n] = 0;
	if((dp = opendir(pathname)) == NULL)
	{
		printf("opendir error\n");
		return -1;
	}
	printf("%s:\n",pathname);
	while((dirp = readdir(dp)) != NULL)
	{
		if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0) // 跳过递归遍历.和..防止死循环
		{
			if(getOPT[E_a] == 1 && getOPT[E] == 1)
			       printf("%s\n",dirp->d_name);
			if(getOPT[E_a] == 1 && getOPT[E_l] == 1)
				rprintl(dirp->d_name,bufstat);	
			continue;
		}
		strcpy(&pathname[n],dirp->d_name);
		query_r(pathname);
	}
	pathname[n] = 0;
	closedir(dp);
}
const char* func(const char* pathname) // 去除文件名前相应的路径
{
	if(pathname[0] == '.')
		return pathname;
	const char*p = &pathname[strlen(pathname)-1];
	while(*p!='/')
		--p;
	return p+1;
}
void rprintl(const char*pathname,struct stat bufstat)
{
	struct tm *p;
	p = gmtime(&(bufstat.st_ctim.tv_sec));
	printf("%d/%d/%d\t%2d:%2d:%2d\t",(1900+p->tm_year),1+p->tm_mon,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
	printf("\t\t%s\n",func(pathname));
}
void rprint(const char* pathname)
{
	printf("%s\n",func(pathname));
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值