返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++实现简单的ls命令及其原理
  • 742
分享到

C++实现简单的ls命令及其原理

C++ls命令格式C++ls命令 2023-05-19 14:05:54 742人浏览 八月长安
摘要

目录思维导图准备工作对控制参数的处理对dir参数的处理函数实现实现完整代码总结思维导图 准备工作 对控制参数的处理 一共有 7 个可选参数,分别是-a、-l、-R、-t、-r、-i

思维导图

准备工作

对控制参数的处理

一共有 7 个可选参数,分别是-a、-l、-R、-t、-r、-i、-s,这些参数可以相互自由组合,因此可以设计一种机制,就是直接把它们全部用循环一次性做或运算,得到一个参数标记Vec。

// 标记: -a、-l、-R、-t、-r、-i、-s 参数(向量分量)
#define a 0b1000000
#define l 0b0100000
#define R 0b0010000
#define t 0b0001000
#define r 0b0000100
#define I 0b0000010
#define s 0b0000001
// 向量
int Vec = 0;

而 Vec 可以使用全局变量,这样可以避免写函数时不断地给函数参数加入地址参数,使得更加代码整洁,更直观。

对dir参数的处理

同理,依然可以设计一个全局容器,不断地把 dirname 扔进去:

char* dirname[4096 * 128];
int dirlen = 0;

而对于 filename 也是一样的,但在每次遍历一个dir 之前,就得filename 容器做重置处理:

char* filenames[4096 * 128];
int file_cnt = 0;

函数实现

void tags_cal(int arGC, char* argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] !=
            '-') {  // 只接受以'-'开头的参数,其它参数要么错误,要么是文件夹名称或文件名
            char* tempdirname = (char*)malloc(sizeof(char) * 4096);
            strcpy(tempdirname, argv[i]);
            dirname[dirlen++] = tempdirname;
        } else {
            int len = strlen(argv[i]);
            for (int j = 1; j < len; j++) {
                switch (argv[i][j]) {
                    case 'a':
                        Vec |= a;
                        break;
                    case 'l':
                        Vec |= l;
                        break;
                    case 'R':
                        Vec |= R;
                        break;
                    case 't':
                        Vec |= t;
                        break;
                    case 'r':
                        Vec |= r;
                        break;
                    case 'i':
                        Vec |= I;
                        break;
                    case 's':
                        Vec |= s;
                        break;
                    default:
                        fprintf(stderr, "%c参数错误!\n", argv[i][j]);
                        break;
                }
            }
        }
    }
    if (dirlen == 0) {
        dirlen = 1;
        char* tempdirname = (char*)malloc(sizeof(char) * 2048);
        strcpy(tempdirname, ".");
        dirname[0] = tempdirname;
    }
}

这里需要注意的是,如果dirlen == 0,说明我们的命令并没有加参数,默认是对当前文件夹进行操作,因此需要重新对 dirlen赋值为 1,然后把 dirname[0]置为"."

实现

我们上一步成功得到了,dirnnamedirlen,这样就可以逐个dirname[i]进行处理了!

void do_myls() {
    for (int i = 0; i < dirlen; i++) {
        if (do_name(dirname[i]) == -1) {
            continue;
        }
        // 且自动字典排序
        if ((Vec & t) == t) {  // 时间排序
            do_t(filenames);
        }
        if ((Vec & r) == r) {  // 逆序
            do_r(filenames, file_cnt);
        }
        printf("当前路径:\"%s\"\n", dirname[i]);
        int tag = 0;  // 换行
        for (int j = 0; j < file_cnt; j++) {
            // 拼凑文件名
            char path[4096] = {0};
            strcpy(path, dirname[i]);
            int len = strlen(dirname[i]);
            strcpy(&path[len], "/");
            strcpy(&path[len + 1], filenames[j]);
            tag++;
            if ((Vec & a) == 0) {
                if ((strcmp(filenames[j], ".") == 0 ||
                     strcmp(filenames[j], "..") == 0) ||
                    filenames[j][0] == '.') {
                    continue;
                }
            }
            struct stat info;
            stat(path, &info);  // 拉进 info
            if (S_ISDIR(info.st_mode) && ((Vec & R) == R)) {
                // 如果是目录,那就直接拉进 dirnames:"dirname/filename"
                char* tempdirname = (char*)malloc(sizeof(char) * 4096);
                strcpy(tempdirname, dirname[i]);
                int len = strlen(tempdirname);
                strcpy(&tempdirname[len], "/");
                strcpy(&tempdirname[len + 1], filenames[j]);
                dirname[dirlen++] = tempdirname;
            }
            if ((Vec & I) == I) {
                do_i(path);
            }
            if ((Vec & s) == s) {
                do_s(path);
            }
            if ((Vec & l) == 0) {
                if (S_ISDIR(info.st_mode))  // 判断是否为目录
                {
                    printf(GREEN "%s\t" NONE, filenames[j]);
                } else {
                    printf(BLUE "%s\t" NONE, filenames[j]);
                }
            }
            if ((Vec & l) == l) {
                void mode_to_letters();
                char modestr[11];
                mode_to_letters(info.st_mode, modestr);
                printf("%s ", modestr);
                printf("%4d ", (int)info.st_nlink);
                printf("%-8s ", uid_to_name(info.st_uid));
                printf("%-8s ", gid_to_name(info.st_gid));
                printf("%8ld ", (long)info.st_size);
                printf("%.12s ", ctime(&info.st_mtime));
                if (S_ISDIR(info.st_mode))  // 判断是否为目录
                {
                    printf(GREEN "%s\t" NONE, filenames[j]);
                } else {
                    printf(BLUE "%s\t" NONE, filenames[j]);
                }
                printf("\n");
            }
            if ((tag % 5 == 0) && ((Vec & l) == 0)) {
                printf("\n");
            }
        }
        // 清空容器
        for (int k = 0; k < file_cnt; k++) {
            memset(filenames[k], 4096, '\0');
        }
        file_cnt = 0;
    }
}

这里最关键的就是对-R参数的处理,因为我们的整体框架并不适合做函数的递归,因此我们可以在判断某个 filename是一个 dir 之后,就可以把它加入到 dirname 中,并且把 dirlen++,这样就在逻辑上实现了遍历,这里也充分利用了全局变量的优势:牵一发而动全身。

struct stat info;
            stat(path, &info);  // 拉进 info
            if (S_ISDIR(info.st_mode) && ((Vec & R) == R)) {
                // 如果是目录,那就直接拉进 dirnames:"dirname/filename"
                char* tempdirname = (char*)malloc(sizeof(char) * 4096);
                strcpy(tempdirname, dirname[i]);
                int len = strlen(tempdirname);
                strcpy(&tempdirname[len], "/");
                strcpy(&tempdirname[len + 1], filenames[j]);
                dirname[dirlen++] = tempdirname;
            }

而其它的功能性函数实现起来就很简单了,就不累赘了。

完整代码

#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
// 标记: -a、-l、-R、-t、-r、-i、-s 参数(向量分量)
#define a 0b1000000
#define l 0b0100000
#define R 0b0010000
#define t 0b0001000
#define r 0b0000100
#define I 0b0000010
#define s 0b0000001
// 颜色宏
#define NONE "\033[m"
#define GREEN "\033[0;32;32m"
#define BLUE "\033[0;32;34m"
// 函数声明
void tags_cal(int argc, char* argv[]);
void restored_ls(struct dirent* cur_item);
void sort(char** filenames, int start, int end);
void do_r(char** filenames, int file_cnt);
int partition(char** filenames, int start, int end);
void swap(char** s1, char** s2);
int compare(char* s1, char* s2);
char* uid_to_name(uid_t);
char* gid_to_name(gid_t);
void mode_to_letters(int, char[]);
char* uid_to_name(uid_t);
// ********函数声明********
void do_i(char filename[]);
void do_s(char filename[]);
int do_name(char dirname[]);
void do_myls();
void do_t(char** filenames);
int Vec = 0;
char* dirname[4096 * 128];
int dirlen = 0;
char* filenames[4096 * 128];
int file_cnt = 0;
int main(int argc, char* argv[]) {
    tags_cal(argc, argv);
    do_myls();
    return 0;
}
void do_myls() {
    for (int i = 0; i < dirlen; i++) {
        if (do_name(dirname[i]) == -1) {
            continue;
        }
        // 且自动字典排序
        if ((Vec & t) == t) {  // 时间排序
            do_t(filenames);
        }
        if ((Vec & r) == r) {  // 逆序
            do_r(filenames, file_cnt);
        }
        printf("当前路径:\"%s\"\n", dirname[i]);
        int tag = 0;  // 换行
        for (int j = 0; j < file_cnt; j++) {
            // 拼凑文件名
            char path[4096] = {0};
            strcpy(path, dirname[i]);
            int len = strlen(dirname[i]);
            strcpy(&path[len], "/");
            strcpy(&path[len + 1], filenames[j]);
            tag++;
            if ((Vec & a) == 0) {
                if ((strcmp(filenames[j], ".") == 0 ||
                     strcmp(filenames[j], "..") == 0) ||
                    filenames[j][0] == '.') {
                    continue;
                }
            }
            struct stat info;
            stat(path, &info);  // 拉进 info
            if (S_ISDIR(info.st_mode) && ((Vec & R) == R)) {
                // 如果是目录,那就直接拉进 dirnames:"dirname/filename"
                char* tempdirname = (char*)malloc(sizeof(char) * 4096);
                strcpy(tempdirname, dirname[i]);
                int len = strlen(tempdirname);
                strcpy(&tempdirname[len], "/");
                strcpy(&tempdirname[len + 1], filenames[j]);
                dirname[dirlen++] = tempdirname;
            }
            if ((Vec & I) == I) {
                do_i(path);
            }
            if ((Vec & s) == s) {
                do_s(path);
            }
            if ((Vec & l) == 0) {
                if (S_ISDIR(info.st_mode))  // 判断是否为目录
                {
                    printf(GREEN "%s\t" NONE, filenames[j]);
                } else {
                    printf(BLUE "%s\t" NONE, filenames[j]);
                }
            }
            if ((Vec & l) == l) {
                void mode_to_letters();
                char modestr[11];
                mode_to_letters(info.st_mode, modestr);
                printf("%s ", modestr);
                printf("%4d ", (int)info.st_nlink);
                printf("%-8s ", uid_to_name(info.st_uid));
                printf("%-8s ", gid_to_name(info.st_gid));
                printf("%8ld ", (long)info.st_size);
                printf("%.12s ", ctime(&info.st_mtime));
                if (S_ISDIR(info.st_mode))  // 判断是否为目录
                {
                    printf(GREEN "%s\t" NONE, filenames[j]);
                } else {
                    printf(BLUE "%s\t" NONE, filenames[j]);
                }
                printf("\n");
            }
            if ((tag % 5 == 0) && ((Vec & l) == 0)) {
                printf("\n");
            }
        }
        // 清空容器
        for (int k = 0; k < file_cnt; k++) {
            memset(filenames[k], 4096, '\0');
        }
        file_cnt = 0;
    }
}
void tags_cal(int argc, char* argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] !=
            '-') {  // 只接受以'-'开头的参数,其它参数要么错误,要么是文件夹名称或文件名
            char* tempdirname = (char*)malloc(sizeof(char) * 4096);
            strcpy(tempdirname, argv[i]);
            dirname[dirlen++] = tempdirname;
        } else {
            int len = strlen(argv[i]);
            for (int j = 1; j < len; j++) {
                switch (argv[i][j]) {
                    case 'a':
                        Vec |= a;
                        break;
                    case 'l':
                        Vec |= l;
                        break;
                    case 'R':
                        Vec |= R;
                        break;
                    case 't':
                        Vec |= t;
                        break;
                    case 'r':
                        Vec |= r;
                        break;
                    case 'i':
                        Vec |= I;
                        break;
                    case 's':
                        Vec |= s;
                        break;
                    default:
                        fprintf(stderr, "%c参数错误!\n", argv[i][j]);
                        break;
                }
            }
        }
    }
    if (dirlen == 0) {
        dirlen = 1;
        char* tempdirname = (char*)malloc(sizeof(char) * 2048);
        strcpy(tempdirname, ".");
        dirname[0] = tempdirname;
    }
}
void do_i(char filename[]) {
    struct stat info;
    if (stat(filename, &info) == -1)
        perror(filename);
    printf("%llu\t", info.st_ino);
}
void do_s(char filename[]) {
    struct stat info;
    if (stat(filename, &info) == -1)
        perror(filename);
    printf("%4llu\t", info.st_size / 4096 * 4 + (info.st_size % 4096 ? 4 : 0));
}
int do_name(char dirname[]) {
    int i = 0;
    int len = 0;
    DIR* dir_ptr;
    struct dirent* direntp;
    if ((dir_ptr = opendir(dirname)) == NULL) {
        fprintf(stderr, "权限不够,cannot open: %s\n", dirname);
        return -1;
    } else {
        while ((direntp = readdir(dir_ptr))) {
            restored_ls(direntp);
        }
        sort(filenames, 0, file_cnt - 1);
    }
    printf("\n");
    closedir(dir_ptr);
    return 1;
}
void sort(char** filenames, int start, int end) {
    if (start < end) {
        int position = partition(filenames, start, end);
        sort(filenames, start, position - 1);
        sort(filenames, position + 1, end);
    }
}
int partition(char** filenames, int start, int end) {
    if (!filenames)
        return -1;
    char* privot = filenames[start];
    while (start < end) {
        while (start < end && compare(privot, filenames[end]) < 0)
            --end;
        swap(&filenames[start], &filenames[end]);
        while (start < end && compare(privot, filenames[start]) >= 0)
            ++start;
        swap(&filenames[start], &filenames[end]);
    }
    return start;
}
void swap(char** s1, char** s2) {
    char* tmp = *s1;
    *s1 = *s2;
    *s2 = tmp;
}
int compare(char* s1, char* s2) {
    if (*s1 == '.')
        s1++;
    if (*s2 == '.')
        s2++;
    while (*s1 && *s2 && *s1 == *s2) {
        ++s1;
        ++s2;
        if (*s1 == '.')
            s1++;
        if (*s2 == '.')
            s2++;
    }
    return *s1 - *s2;
}
void restored_ls(struct dirent* cur_item) {
    char* result = (char*)malloc(sizeof(char) * 4096);
    strcpy(result, cur_item->d_name);
    filenames[file_cnt++] = result;
}
void mode_to_letters(int mode, char str[]) {
    strcpy(str, "----------");
    if (S_ISDIR(mode))
        str[0] = 'd';
    if (S_ISCHR(mode))
        str[0] = 'c';
    if (S_ISBLK(mode))
        str[0] = 'b';
    if (mode & S_IRUSR)
        str[1] = 'r';
    if (mode & S_IWUSR)
        str[2] = 'w';
    if (mode & S_IXUSR)
        str[3] = 'x';
    if (mode & S_IRGRP)
        str[4] = 'r';
    if (mode & S_IWGRP)
        str[5] = 'w';
    if (mode & S_IXGRP)
        str[6] = 'x';
    if (mode & S_IROTH)
        str[7] = 'r';
    if (mode & S_IWOTH)
        str[8] = 'w';
    if (mode & S_IXOTH)
        str[9] = 'x';
}
char* gid_to_name(gid_t gid) {
    struct group *getgrgid(), *grp_ptr;
    static char numstr[10];
    if ((grp_ptr = getgrgid(gid)) == NULL) {
        sprintf(numstr, "%d", gid);
        return numstr;
    } else {
        return grp_ptr->gr_name;
    }
}
char* uid_to_name(gid_t uid) {
    struct passwd* getpwuid();
    struct passwd* pw_ptr;
    static char numstr[10];
    if ((pw_ptr = getpwuid(uid)) == NULL) {
        sprintf(numstr, "%d", uid);
        return numstr;
    } else {
        return pw_ptr->pw_name;
    }
}
void do_t(char** filenames) {
    char temp[2048] = {0};
    struct stat info1;
    struct stat info2;
    for (int i = 0; i < file_cnt - 1; i++) {
        for (int j = i + 1; j < file_cnt; j++) {
            stat(filenames[i], &info1);
            stat(filenames[j], &info2);
            if (info1.st_mtime < info2.st_mtime) {
                strcpy(temp, filenames[i]);
                strcpy(filenames[i], filenames[j]);
                strcpy(filenames[j], temp);
            }
        }
    }
}
void do_r(char** arr, int file_cnt) {
	// 只需要修改指针
    char left = 0;              
    char right = file_cnt - 1;  
    char temp;
    while (left < right) {
        char* temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
        left++;   
        right--; 
    }
}

总结

这个 myls的难点在于整个系统的设计,比如参数怎么处理,怎么根据参数输出相应的信息。而函数的实现就比较简单。

到此这篇关于c++实现简单的ls命令及其原理的文章就介绍到这了,更多相关C++ ls命令内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++实现简单的ls命令及其原理

本文链接: https://www.lsjlt.com/news/213390.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++实现简单的ls命令及其原理
    目录思维导图准备工作对控制参数的处理对dir参数的处理函数实现实现完整代码总结思维导图 准备工作 对控制参数的处理 一共有 7 个可选参数,分别是-a、-l、-R、-t、-r、-i...
    99+
    2023-05-19
    C++ ls命令格式 C++ ls命令
  • C++和python实现单链表及其原理
    目录一、链表的基本概念二、单链表1.python实现(1)节点设计(2)链表类:Single_Linked_List(3)判断链表是否为空:is_empty()函数(4)头插法:ad...
    99+
    2024-04-02
  • C语言如何实现ls命令
    这篇文章主要介绍了C语言如何实现ls命令,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。示例如下://// ls.c// apue//// Cre...
    99+
    2023-06-09
  • linux 中的ls命令参数详解及ls命令的使用实例
    一、ls命令参数详解 可以通过阅读 ls 的说明书页(man ls)来获得选项的完整列表。 -a 全部(all)。列举目录中的全部文件,包括隐藏文件(.filename)。位于这个列表的起首处的 ...
    99+
    2022-06-04
    命令 详解 实例
  • C++中内存池的简单原理及实现详解
    目录为什么要用内存池内存池原理内存池设计内存池实现为什么要用内存池 C++程序默认的内存管理(new,delete,malloc,free)会频繁地在堆上分配和释放内存,导致性能的损...
    99+
    2023-03-01
    C++内存池原理 C++实现内存池 C++内存池
  • C语言实现的ls命令源码分享
    在之前的一些看书或者学习中,一直有一种感觉有问题的态度,那就是认为看懂了,但是不动手,感觉这样看书的效果不是很大。ls命令估计是我们在linux/unix里面用的最多的一个命令了,我们就用c来简单的实现一下...
    99+
    2022-06-04
    源码 命令 语言
  • 【C++】多态的实现及其底层原理
    个人主页:🍝在肯德基吃麻辣烫 我的gitee:gitee仓库 分享一句喜欢的话:热烈的火焰,冰封在最沉默的火山深处。 文章目录 前言一、什么是多态?二、多态的构成条件2.1什么是虚函数?2.2虚函数的重...
    99+
    2023-08-17
    c++ 开发语言 多态
  • 工厂模式原理及其简单应用
    结合简单示例和UML图,讲解工厂模式简单原理。[@more@]一、引子话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰)、Bmw(宝马)、Audi(奥迪)看来这人比较爱国,没有日本车),还雇了司机为他开车。不过,爆发户坐车时总是这样...
    99+
    2023-06-03
  • Redis 命令的详解及简单实例
    Redis 命令的详解及简单实例 Redis 命令用于在 redis 服务上执行操作。 要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的...
    99+
    2022-06-04
    详解 实例 命令
  • JavaScript中Promise的简单使用及其原理详解
    Promise是ES6最重要的特性之一,今天来系统且细致的研究一下Promise的用法以及原理。 按照我往常的理解,Promise是一个构造函数,有all、resolve、rejec...
    99+
    2023-03-23
    JavaScript Promise原理 JavaScript Promise使用 JavaScript Promise
  • 聊聊Vue指令的基本原理及其实现
    Vue中的指令(Directive)是一种特殊的语法,用于在页面中对元素进行控制和渲染。指令的实现原理是Vue框架中的重要组成部分,本文将介绍Vue指令的基本原理及其实现。指令的基本原理指令是Vue框架中的一个重要概念,用于定义页面中元素的...
    99+
    2023-05-14
  • 详解Dijkstra算法原理及其C++实现
    目录什么是最短路径问题Dijkstra算法实现思路案例分析代码实现什么是最短路径问题 如果从图中某一顶点(称为源点)到达另一顶点(称为终点)的路径可能不止一条,如何找到一条路径使得沿...
    99+
    2024-04-02
  • 简述traceroute命令的原理
    Traceroute命令是用于诊断网络上的数据包传输路径的工具。它通过发送一系列的ICMP回显请求报文,并在每次请求报文的时间戳上增...
    99+
    2023-09-15
    traceroute
  • CRC校验原理及其C语言实现详解
    目录前言CRC算法简介CRC参数模型CRC计算CRC校验CRC计算的C语言实现CRC计算工具总结前言 最近的工作中,要实现对通信数据的CRC计算,所以花了两天的时间好好研究了一下,周...
    99+
    2023-03-10
    C语言 CRC校验 C语言 CRC原理 C语言 CRC
  • Golang中的类型断言机制简介及其实现原理
    Golang中的断言机制简介及其实现原理 概述:在Golang中,断言(Assertion)是一种用于确定接口类型的方法。它用于检查接口是否满足某个具体的类型,并在满足时将接口转换为该具体类型。断言机制在Go...
    99+
    2024-01-29
    断言机制简介 断言机制实现原理
  • 浅谈线性表的原理及简单实现方法
    一、线性表原理:零个或多个同类数据元素的有限序列原理图:特点 :有序性有限性同类型元素第一个元素无前驱,最后一个元素无后继,中间的元素有一个前驱并且有一个后继线性表是一种逻辑上的数据结构,在物理上一般有两种实现 顺序实现和链表实现二、基于数...
    99+
    2023-05-31
    线性表
  • 二进制加密PHP Webshell原理及简单实现
    今天继续给大家介绍渗透测试相关知识,本文主要内容是二进制加密PHP Webshell原理及简单实现。 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后...
    99+
    2023-09-20
    Webshell Web安全 PHP 加密 渗透测试
  • 常用的MySQL命令简单整理
    本篇内容介绍了“常用的MySQL命令简单整理”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  1、显示数据...
    99+
    2024-04-02
  • 详解Vue中双向绑定原理及简单实现
    目录监听器订阅器双向绑定构造函数编译器(1)Compile类(2)node2Fragment函数(3)compile函数总结效果完整代码代码缺陷监听器 vue实现双向绑定时,首先要实...
    99+
    2023-05-19
    Vue双向绑定原理 Vue实现双向绑定 Vue双向绑定
  • Linux nohup命令原理及实例解析
    nohup命令 在应用Unix/Linux时,我们一般想让某个程序在后台运行,于是我们将常会用 & 在程序结尾来让程序自动运行。比如我们要运行mysql在后台: /usr/local/mysql/bin/m...
    99+
    2022-06-03
    Linux nohup 命令
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作