linux 遍历目录文件 list命令 c语言实现

任务描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

源代码(list.c)

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

#define DEBUG_STD_OUTPUT  

#define atoi_64(__str__) strtoll(__str__, NULL, 10)

#define IS_NUMBER_STR(__STRING__) strspn(__STRING__, "0123456789") == strlen(__STRING__)
	
#if defined(DEBUG_STD_OUTPUT)
	#define LOG_IF_ENABLE(...) \
		printf(__VA_ARGS__);
#else
	#define LOG_IF_ENABLE(__LOG__)  
#endif

#define FMT_RED(__STR__)	"\033[;31m"__STR__"\033[0m"
#define FMT_BLUE(__STR__)	"\033[;34m"__STR__"\033[0m"
#define FMT_CYAN(__STR__)	"\033[;36m"__STR__"\033[0m"
#define FMT_GREEN(__STR__)	"\033[;32m"__STR__"\033[0m"
#define FMT_BLACK(__STR__)	"\033[;30m"__STR__"\033[0m"
#define FMT_YELLOW(__STR__)	"\033[;37m"__STR__"\033[0m"

enum LIST_COMMAND_ARG_INFO {
	ARG_NO_ATTACHED_BIT 		= 0,
	ARG_SHOW_RECURSIVE_BIT 		= 1,
	ARG_SHOW_HIDDEN_BIT 		= 1 << 1,
	ARG_SET_MINIMUM_BIT 		= 1 << 2,
	ARG_SET_MAXIMUM_BIT 		= 1 << 3,
	ARG_SET_CHANGETIME_LMT_BIT 	= 1 << 4
};

typedef struct {
	enum LIST_COMMAND_ARG_INFO 	argInfo;
	uint32_t 					minimumSize;
	uint32_t					maximumSize;
	uint32_t					modifiedLmt;
} ListCommandInfo;

typedef struct dirent* DirentPtr;

extern int getcwd(char*, int);
static ListCommandInfo dealWithArguments(int argc, char* argv[]);
static void handleDir(const char* dirPath, const ListCommandInfo* pInfo);
static void displayDirInfo(DIR* pDIR, const ListCommandInfo* pInfo, const char* curPath);
static void handleFile(struct stat* pFileInfo, const char* pFilename, const ListCommandInfo* pCmdInfo);

static char listPathRoot[PATH_MAX] = {0};

int main(int argc, char* argv[]) {
	// 获取工作目录到全局变量
    getcwd(listPathRoot, sizeof(listPathRoot));
	/** 
	 * 要想扩展list命令到支持文件夹&文件为参数,请自行判别命令行附加参数值为目录或文件后取出
	 * 调用 handleDir / handleFile 即可
	 */

	// 拿到命令行参数
	ListCommandInfo cmdInfo = dealWithArguments(argc, argv);
	// 从pwd开始执行
	handleDir(listPathRoot, &cmdInfo);
	return 0;
}

void displayDirInfo(DIR* pDIR, const ListCommandInfo* pInfo, const char* curPath) {
	char path[PATH_MAX] = {0};

	DirentPtr pDirent = NULL; // 定义readdir函数返回的结构体变量
    // 判断是否读取到目录尾
	while((pDirent = readdir(pDIR)) > 0) {
		// 定义stat函数返回的结构体变量
		struct stat fileMessage = {};
		// 获取文件名
        char* filename = pDirent->d_name;
		// 处理path字符串
		{
			int end = 0; 
        	while (curPath[end]) {
            	end++;
			}
        	strcpy(path, curPath);
        	if (curPath[end - 1] != '/')
        	    strcat(path, "/");
        	strcat(path, filename);

			
			// 获取文件信息
        	int statStatus = lstat(path, &fileMessage);
        	// stat读取文件错误则输出提示信息
			if(statStatus == -1) {
            	return;
				// exit(-5);
			}
		}
		
		// 判断是否输出当前目录、上一级目录与隐藏文件
		if (pInfo->argInfo & ARG_SHOW_HIDDEN_BIT) {
			if (S_ISDIR(fileMessage.st_mode)) {
				if (filename[0] != '.')
					printf(FMT_BLUE("%s")"\t", filename);
				else
					printf(FMT_RED("%s")"\t", filename);
			} else {
				handleFile(&fileMessage, filename, pInfo);
			}
		} else {
			if (filename[0] != '.') {
            	if (S_ISDIR(fileMessage.st_mode)) {
					printf(FMT_BLUE("%s")"\t", filename);
				} else {
					handleFile(&fileMessage, filename, pInfo);
				}
			}
		}



    }
	// 将文件流的指针拨回起始位置(因为用到了readdir函数))
    rewinddir(pDIR); 
    putchar('\n'); putchar('\n');
}

static void handleDir(const char* dirPath, const ListCommandInfo* pInfo) {
	// 每进入一个path就先打印全部信息,然后再进入新的path,递归实现深度优先
	char nextpath[PATH_MAX];

    DIR *pDIR = opendir(dirPath);
    if (pDIR == NULL) {
		fprintf(stderr, "FAILED TO OPEN DIR\n");
		exit(-4);
	}

	// 输出当前目录路径
    printf("%s:\n", dirPath);
    // 显示目录内部信息
	displayDirInfo(pDIR, pInfo, dirPath);

    DirentPtr pDirent = NULL;
	// 判断是否读取到目录尾,若读到则while中断
    while((pDirent = readdir(pDIR)) > 0) {
		// 获取文件名
        char* filename = pDirent->d_name; 

		// 优化显示路径(处理"./test/"与"./test")
        int end = 0; 
        while (dirPath[end]) {
            end++;
		}

        strcpy(nextpath, dirPath);
        if (dirPath[end - 1] != '/')
            strcat(nextpath, "/");
        strcat(nextpath, filename);

		// 定义stat函数返回的结构体变量
        struct stat fileMessage = {};
		// 获取文件信息
        int statInfo = lstat(nextpath, &fileMessage);
        // stat读取文件错误则输出提示信息
		if(statInfo == -1) {
            return;
			// exit(-5);
		}
		// 筛选"." & ".."与隐藏目录
        else {
			if (pInfo->argInfo & ARG_SHOW_RECURSIVE_BIT) {
				if (strlen(filename) >= 2) {
					if (S_ISDIR(fileMessage.st_mode)) {
						if (filename[0] == '.' && 
							filename[1] != '.' && 
							(pInfo->argInfo & ARG_SHOW_HIDDEN_BIT)
						) {
							handleDir(nextpath, pInfo);
						} else {
							if (filename[0] != '.') {
								handleDir(nextpath, pInfo);
							}
						}
					}
				} else {
					if (S_ISDIR(fileMessage.st_mode)) {
						if (filename[0] != '.') {
							handleDir(nextpath, pInfo);
						}
					}
				}
			}
        }
    }
    closedir(pDIR);
}

// 用来优化文件打印样式 & 检测文件属性与命令行参数的对应关系
void handleFile(struct stat* pFileInfo, const char* pFilename, const ListCommandInfo* pCmdInfo) {
	// 文件容量 (bytes)
	off_t fileSize 	= pFileInfo->st_size;
	// 最后修改时间
	time_t mtime 	= pFileInfo->st_mtim.tv_sec;
	
	time_t curTime 	= time(NULL);
	
	int printFlag = 1;

	if ((pCmdInfo->argInfo & ARG_SET_MINIMUM_BIT)) {
		if (fileSize < pCmdInfo->minimumSize) {
			printFlag = 0;
		}
	}
	if ((pCmdInfo->argInfo & ARG_SET_MAXIMUM_BIT)) {
		if (fileSize > pCmdInfo->maximumSize) {
			printFlag = 0;
		}
	}
	// 以天为单位
	if ((pCmdInfo->argInfo & ARG_SET_CHANGETIME_LMT_BIT)) {
		if ((curTime - mtime) / 86400 > pCmdInfo->modifiedLmt) {
			printFlag = 0;
		}
	}

	if (printFlag) {
		// 如果为二进制 & 可执行文件
		if (strchr(pFilename, '.') == NULL) {
			printf(FMT_GREEN("%s")"\t", pFilename);
		} else {
			printf("%s\t", pFilename);
		}	
	}
}


#define GET_ARG_VALUE(__ARGUMENT__) \
	if (IS_NUMBER_STR(argv[i])) { \
		__ARGUMENT__ = atoi_64(argv[i]); \
	} else { \
		fprintf( \
			stderr, \
			"INPUT ARGUMENT ["#__ARGUMENT__ "]: \"%s\" " \
			"CANNOT BE CONVERTED INTO UNSIGNED INTEGER\n\n", argv[i]); \
		exit(-3); \
	}

#define INC_CHECK_INDEX \
	i++;				\
	if (i >= argc) { 	\
		exit(-2);		\
	}

// 处理命令行参数
ListCommandInfo dealWithArguments(int argc, char* argv[]) {
	// just for fun
	if (argc < 1) {
		exit(-1);
	}
	putchar('\n');

	int i = 0;

	ListCommandInfo cmdInfo = {};

	enum LIST_COMMAND_ARG_INFO argInfo = ARG_NO_ATTACHED_BIT;
	uint32_t minimumSize = 0,
			 maximumSize = 0 - 1,
			 modifiedLmt = 0 - 1;

	for (i = 1; i < argc; i++) {
		// 递归处理模式
		if (strcmp(argv[i], "-r") == 0) {
			if ((argInfo & ARG_SHOW_RECURSIVE_BIT) > 0) {
				fprintf(stderr, "FAILED TO REBIND ARG: -r\n\n");
				exit(-2);			
			} else {
				argInfo = argInfo | ARG_SHOW_RECURSIVE_BIT;
			}
		// 处理隐藏文件
		} else if (strcmp(argv[i], "-a") == 0) {
			if ((argInfo & ARG_SHOW_HIDDEN_BIT) > 0) {
				fprintf(stderr, "FAILED TO REBIND ARG: -a\n\n");
				exit(-2);
			} else {
				argInfo = argInfo | ARG_SHOW_HIDDEN_BIT;
			}
		// 引入文件大小最小值参数
		} else if (strcmp(argv[i], "-l") == 0) {
			if ((argInfo & ARG_SET_MINIMUM_BIT) > 0) {
				fprintf(stderr, "FAILED TO REBIND ARG: -l\n\n");
				exit(-2);
			} else {
				INC_CHECK_INDEX;
				GET_ARG_VALUE(minimumSize);
				argInfo = argInfo | ARG_SET_MINIMUM_BIT;
			}
		// 引入文件大小最大值参数
		} else if (strcmp(argv[i], "-h") == 0) {
			if ((argInfo & ARG_SET_MAXIMUM_BIT) > 0) {
				fprintf(stderr, "FAILED TO REBIND ARG: -h\n\n");
				exit(-2);
			} else {
				INC_CHECK_INDEX;
				GET_ARG_VALUE(maximumSize);
				argInfo = argInfo | ARG_SET_MAXIMUM_BIT;
			}
		// 引入限定文件最近修改时间参数
		} else if (strcmp(argv[i], "-m") == 0) {
			if ((argInfo & ARG_SET_CHANGETIME_LMT_BIT) > 0) {
				fprintf(stderr, "FAILED TO REBIND ARG: -m\n\n");
				exit(-2);
			} else {
				INC_CHECK_INDEX;
				GET_ARG_VALUE(modifiedLmt);
				argInfo = argInfo | ARG_SET_CHANGETIME_LMT_BIT;
			}

		} else if (strcmp(argv[i], "--") == 0) {
			break;
		} else {
			fprintf(stderr, "PLEASE CHECK THIS INPUT COMMAND ARGUMENTS: \"%s\"\n\n", argv[i]);
		}
	}
	cmdInfo.argInfo 	= argInfo;
	cmdInfo.maximumSize = maximumSize;
	cmdInfo.modifiedLmt = modifiedLmt;
	cmdInfo.minimumSize = minimumSize;

	if (maximumSize < minimumSize) {
		fprintf(stderr, "[MAX SIZE:%u bytes] CAN NOT BE LESS THAN [MIN SIZE:%u bytes]!\n\n", maximumSize, minimumSize);
		exit(-6);
	}

#if defined(DEBUG_STD_OUTPUT)
	char inputArguments[512] = "ENABLED MODE: \n";
	if (argInfo & ARG_SHOW_RECURSIVE_BIT) {
		sprintf(inputArguments + strlen(inputArguments), "\t[SHOW RECURSIVE]\n");
	}
	if (argInfo & ARG_SHOW_HIDDEN_BIT) {
		sprintf(inputArguments + strlen(inputArguments), "\t[SHOW HIDDEN]\n");
	}
	if (argInfo & ARG_SET_MINIMUM_BIT) {
		sprintf(inputArguments + strlen(inputArguments), "\t[WITH MINIMUM FILE SIZE(%u bytes)]\n", minimumSize);
	}
	if (argInfo & ARG_SET_MAXIMUM_BIT) {
		sprintf(inputArguments + strlen(inputArguments), "\t[WITH MAXIMUM FILE SIZE(%u bytes)]\n", maximumSize);
	}
	if (argInfo & ARG_SET_CHANGETIME_LMT_BIT) {
		sprintf(inputArguments + strlen(inputArguments), "\t[WITH MAXIMUM MODIFY TIME LIMIT(%u days)]\n", modifiedLmt);
	}

	printf("ABSOLUTE EXECUTE PATH: %s\n%s", listPathRoot, inputArguments);
#endif

	putchar('\n');

	return cmdInfo;
}

测试样例(从上到下由旧到新,实现存在不完整或差异,欢迎补充)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值