• 为Linux 操作系统建立兼容的 Windows命令接口


    简单实现的dos命令

    CLS, DATE,TIME,FIND,FINDSTR,COMP,FC,EXIT,HELP,MORE

    说明

    结构

    为了演示,所用到的两个文档1.txt 2.txt


    CLS

    功能

    cls命令的功能是清屏

    设计流程


    其实就是简单地 fputs("x1b[2Jx1b[H", stdout);其中的不明所以的字符串是VT100的控制码,部分定义如下
    "x1b[2J"清除整个屏幕,行属性变成单宽单高,光标位置不变
    "x1b[H"光标移动
    33[0m 关闭所有属性
    33[1m 设置为高亮
    33[4m 下划线
    33[5m 闪烁
    33[7m 反显
    33[8m 消隐
    33[nA 光标上移 n 行
    33[nB 光标下移 n 行
    33[nC 光标右移 n 行
    33[nD 光标左移 n 行
    33[y;xH 设置光标位置
    33[2J 清屏
    33[K 清除从光标到行尾的内容
    33[s 保存光标位置
    33[u 恢复光标位置
    33[?25l 隐藏光标
    33[?25h 显示光标
    33[30m – 33[37m 设置前景色

    效果


    DATE

    功能

    date 命令用来查看和修改当前日期
    详细操作查看https://jingyan.baidu.com/article/1974b2893e7d62f4b1f774ff.html

    设计流程


    判断是否有输入参数t,?,进行相关处理。
    如果没有则打印当前日期,并提示输入更改日期,判断日期是否合法再进行修改
    判断年月日是否合法直接用了这位博主的代码
    https://blog.csdn.net/freeape/article/details/48682411

    效果


    TIME

    功能

    time 用来查看和修改计算机时间
    详细操作查看https://jingyan.baidu.com/article/aa6a2c14ab5ac90d4c19c492.html

    设计流程


    判断是否有输入参数t,?,进行相关处理。
    如果没有则打印当前时间,并提示输入更改时间,判断时间是否合法再进行修改

    效果

    FIND

    在之后涉及比较的命令的程序都参考了https://zhidao.baidu.com/question/237942227.html下一骑当后的回答

    功能

    find 命令用于查找文档中的特定字符和数字及行号
    详细操作查看https://jingyan.baidu.com/article/86f4a73ecfe08637d65269ef.html

    设计流程


    采用指针遍历文件的匹配算法来寻找字符串,并通过输入参数/C/N/V等控制输出打印的形式

    效果

    FINDSTR

    这个命令自己实现的并不完全

    功能

    findstr是find的升级版
    详细操作查看https://jingyan.baidu.com/article/a65957f418641e24e67f9b99.html

    设计流程



    命令所需参数有文件路径,文件类型和所搜寻的字符串
    该模块包含两个函数
    findstr函数如上图1,主要负责遍历目录与文件,挑选符合参数决定的文件类型
    find1函数如上图2,主要负责采用指针遍历文件,与参数决定的字符串进行对比,找到所匹配的字符串。每次读取一行采用指针遍历方法与字符串进行对比
    对于文件的遍历和文件类型的识别参考了
    https://zhidao.baidu.com/question/683010229831852652.html
    https://www.cnblogs.com/xudong-bupt/p/3504442.html
    以下是我的程序

    while ((ptr = readdir(dir)) != NULL)
        {
            if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) //是当前目录和父目录
                continue;
            else if (ptr->d_type == 4) //是dir
            {
                char *cpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
                strcpy(cpath, path);
                strcat(cpath, "/");
                strcat(cpath, ptr->d_name);
                //findstr(cpath, type, str);
            }
            else//是文件
            {
                p = strrchr(ptr->d_name, '.');//取得文件最后一个.后的字符,即文件的类型
                sprintf(ftype, "%s", p);
                if (strcmp(ftype, type) == 0)
                {
                    char *fpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
                    strcpy(fpath, path);
                    strcat(fpath, "/");
                    strcat(fpath, ptr->d_name);
                    find1(fpath, str);
                }
            }
        }
    

    使用readdir()返回一个结构

    struct dirent
    {
    ino_t d_ino;
    ff_t d_off;
    signed short int d_reclen;
    unsigned char d_type;
    har d_name[256];
    };
    

    d_ino 此目录进入点的inode
    d_off 目录文件开头至此目录进入点的位移
    d_reclen _name的长度,不包含NULL字符
    d_type 所指的文件类型
    d_name 文件名

    效果

    COMP

    该命令要求两个文件的大小相同,获取文件大小的方法参考了https://www.cnblogs.com/xudong-bupt/p/3506772.html

    功能

    comp逐字节比较两个文件或文件集的内容
    详细操作查看https://jingyan.baidu.com/article/90808022da9bbbfd91c80f1b.html](https://jingyan.baidu.com/article/90808022da9bbbfd91c80f1b.html)

    设计流程




    主要包含三个函数comp,command_comp,file_comp分别对应上图1,2,3
    comp主要通过控制流程控制程序走向
    command_comp主要对输入的参数进行分析,并返回一个和(包含参数信息,/L对应1,/A对应2,/D对应4,无对应0)
    file_comp主要通过匹配算法进行字符串的查找,并根据对参数指令的分析返回的值进行打印输出

    效果

    FC

    功能

    FC是DOS及Windows下的一个比较文件的命令行工具,使用该命令能够将两个类似文件的不同之处进行详细对比。
    详细操作查看https://baike.baidu.com/item/FC/10362340?fr=aladdin

    设计流程


    比较两个文件的不同之处,循环读取文件1的一行,与文件2的每一行进行对比,输出不相等的行。再循环读取文件2的一行,与文件1的每一行进行对比,输出不相等的行。

    效果

    EXIT

    功能

    退出当前命令窗口
    详细操作查看https://baike.baidu.com/item/FC/10362340?fr=aladdin

    设计流程


    这里实在不会实现,只好假装实现,因为通过命令窗口调用该程序,所以得到该程序的父进程的id,然后将其kill假装实现了exit

    效果

    HELP

    功能

    help列出命令的帮助信息
    详细操作查看https://jingyan.baidu.com/article/ea24bc39d29264da63b33163.html

    设计流程


    直接输入help命令显示所有help信息,通过help+命令,输出对应命令的信息

    效果

    MORE

    功能

    more 命令将文本文档逐行进行显示, 也可显示多个文档, 跳行和显示下几行
    详细操作查看https://jingyan.baidu.com/article/bad08e1e327c3709c85121fa.html
    其实这个程序大部分用了github上的代码,可惜后面找不到出处了

    设计流程


    主要包含more see_more do_more几个函数,这里全部展示在上图。
    more允许打印多个文件,当打印满时,可以通过命令q退出命令,命令m打印更多,命令 打印下一个文件。

    效果


    两个文件时

    M继续显示, 显示下一个文件

    主函数

    设计流程

    效果

    为了模仿windows前面的提示符,通过getcwd()获取当前目录,并显示

    其它说明

    对于格式化显示输出的问题

    保留小数https://blog.csdn.net/qq_36667170/article/details/79265224
    前面补0https://zhidao.baidu.com/question/2272528818662923828.html

    动态开辟多个指针

    参考自https://zhidao.baidu.com/question/1430108991238952819.html

    pArrStr=(char**)malloc(sizeof(char*)*strLen);//动态开辟N个char*指针,然后给pArrStr保存 for(i=0;i<strLen;i++)
    {
    pArrStr[i]=(char*)malloc(255);
    } 
    

    对时间相关模块说明

    其实开始说明中的linux api文档中解释的就可以,并且有相关示例,这个也比较详细https://blog.csdn.net/lhl_blog/article/details/86238140

    相关调用函数清单

    struct tm
    {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
    };
    int tm_sec 代表目前秒数,正常范围为0-59,但允许至61秒 int tm_min 代表目前分数,范围0-59 int tm_hour 从午夜算起的时数,范围为0-23 int tm_mday 目前月份的日数,范围01-31int tm_mon 代表目前月份,从一月算起,范围从0-11 int tm_year 从1900 年算起至今的年数int tm_wday 一星期的日数,从星期一算起,范围为0-6 int tm_yday 从今年1月1日算起至今的天数,范围为0-365 int tm_isdst 日光节约时间的旗标 此函数返回的时间日期未经时区转换,而是UTC时间。
    
    struct timeval{
    long tv_sec; /*秒*/
    long tv_usec; /*微秒*/
    };
    
    struct timezone{
    int tz_minuteswest; /*和Greenwich 时间差了多少分钟*/
    int tz_dsttime; /*日光节约时间的状态*/
    };
    
    time_t time(time_t *t); 返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。
    struct tm *localtime(const time_t *timep); 将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。
    time_t mktime(strcut tm *timeptr); mktime()用来将参数timeptr所指的tm结构数据转换成从公元1970年1月1日0时0分0 秒算起至今的UTC时间所经过的秒数。
    int stime(long *tp)设置时间。
    int settimeofday(const struct timeval *tv, const struct timezone *tz);设置当前时间。
    

    程序涉及到了很多字符串的操作

    字符串和数字的转化

    https://blog.csdn.net/smile_zhangw/article/details/82051014

    字符串的拼接

    https://www.cnblogs.com/metaphors/p/9409153.html

    相关调用函数清单

    int strcmp(const char *s1, const char *s2);比较两个字符串。
    char *strtok(char *s, const char *delim); strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
    在main()中的使用
    //对命令按空格进行分割,命令存入*argv[]中,命令数存入argc中
            if (strlen(input) != 0)
            {
                char *delim = " ";
                char *p;
                p = strtok(input, delim);
                argv[0] = p;
                while ((p = strtok(NULL, delim)))
                {
                    argv[argc] = p;
                    argc++;
                }
            }
    char *gets(char *s); 由标准输入设备内读进一字符串。
    char *strcpy(char *dest, const char *src); strcpy()会将参数src字符串拷贝至参数dest所指的地址。
    char *strcat(char *dest, const char *src);连接两个字符串。
    char *strchr(const char *s, int c); 查找字符串中第一个出现的指定字符。
    size_t strlen(const char *s);返回字符串长度
    

    对涉及文件相关操作模块说明

    清空缓存

    因为c读取字符时,可能读到缓冲区的字符,产生影响,所以需要清除
    参考https://jingyan.baidu.com/article/9f7e7ec0b5e4a86f28155415.html
    https://zhuanlan.zhihu.com/p/54990226

    相关调用函数清单

    FILE *fopen(const char *path, const char *mode); 参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。
    char *fgets(char *s, int size, FILE *stream);从文件中读取一字符串。
    long ftell(FILE *stream);取得文件流的读取位置。
    struct dirent *readdir(DIR *dir);读取目录。
    int fseek(FILE *stream, long offset, int whence);移动文件流的读写位置。
    int fputs(const char *s, FILE *stream);将一指定字符写入文件内。
    int fgetc(FILE * stream);文件中读取一个字符。
    int getchar(void); getchar()用来从标准输入设备中读取一个字符。然后将该字符从unsigned char转换成int后返回。
    
    

    程序

    gcc -o shell shell.c
    ./shell

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <string.h>
    #include <time.h>
    #include <stdbool.h>
    #include <sys/time.h>
    #include <time.h>
    #include <stdbool.h>
    #include <sys/types.h>
    #include <dirent.h>
    #include <unistd.h>
    //findstr命令
    void find1(char *argv, char *str)
    {
        FILE *fp;
        int stringsize = strlen(str) * sizeof(char);
        char *line = (char *)calloc(512, sizeof(char));
        fp = fopen(argv, "r");
        int i = 0;
        while (fgets(line, 512, fp))
        {
            int j = 0;
            char *start;
            i = 0;
            start = line;
            while (i < ftell(fp) - stringsize)
            {
                j = 0;
                while (*line)
                {
                    if (*str == *line)
                    {
                        str++;
                        line++;
                        j++;
                        continue;
                    }
                    break;
                }
                if (j == stringsize)
                {
                    str = str - j;
                    printf("%s", start);
                    break;
                }
                else
                {
                    str = str - j;
                    line = line - j + 1;
                }
                i++;
            }
        }
    }
    void findstr(char *path, char *type, char *str)
    {
        DIR *dir;
        struct dirent *ptr;
        char *ftype = (char *)malloc(512);
        char *p;
        dir = opendir(path);
        while ((ptr = readdir(dir)) != NULL)
        {
            if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) //是当前目录和父目录
                continue;
            else if (ptr->d_type == 4) //是dir
            {
                char *cpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
                strcpy(cpath, path);
                strcat(cpath, "/");
                strcat(cpath, ptr->d_name);
                //findstr(cpath, type, str);
            }
            else//是文件
            {
                p = strrchr(ptr->d_name, '.');//取得文件最后一个.后的字符,即文件的类型
                sprintf(ftype, "%s", p);
                if (strcmp(ftype, type) == 0)
                {
                    char *fpath = (char *)malloc(strlen(path) + strlen(ptr->d_name) + strlen("/") + 1);
                    strcpy(fpath, path);
                    strcat(fpath, "/");
                    strcat(fpath, ptr->d_name);
                    find1(fpath, str);
                }
            }
        }
    }
    //find命令
    int command_comp1(char **str)
    {
        int i = 3;
        if (strcmp(str[i], "/V") == 0)//包含字符串的所在行,不显示
        {
            return 1;
        }
        else if (strcmp(str[i], "/C") == 0)//只显示包含字符串的行
        {
            return 2;
        }
        else if (strcmp(str[i], "/N") == 0)//显示找到的包含字符串的行数
        {
            return 3;
        }
        else
        {
            printf("命令行参数有误");
            exit(0);
        }
    }
    void find(int argc, char **argv)
    {
        FILE *fp;
        char *string = argv[2];
        int stringsize = strlen(string) * sizeof(char);
        char *line = (char *)calloc(512, sizeof(char));
        fp = fopen(argv[1], "r");
        int i = 0, flag = 0, linec = 1, linen = 0;
        int pa;
        pa = command_comp1(argv);
        while (fgets(line, 512, fp))//读取一行
        {
            int j = 0;
            char *start;
            i = 0;
            start = line;
            while (i < ftell(fp) - stringsize)//将一行的内容与字符串进行比较
            {
    
                j = 0;
                while (*line)
                {
                    if (*string == *line)
                    {
                        string++;
                        line++;
                        j++;
                        continue;
                    }
                    break;
                }
                if (j == stringsize)//比较成功
                {
                    flag = 1;
                    linen++;
                    string = string - j;
                }
                else//比较失败,回退
                {
                    string = string - j;
                    line = line - j + 1;
                }
                i++;
            }
            if (pa == 1)
            {
                if (flag != 1)
                {
                    printf("%s", start);
                }
                else
                {
                    printf("
    ");
                }
            }
            else if (pa == 3)
            {
                if (flag == 1)
                {
                    printf("%d	", linec);
                    printf("%s", start);
                }
            }
            linec++;
            flag = 0;
        }
        if (pa == 2 && linen != 0)
        {
            printf("%d
    ", linen);
        }
    }
    //comp命令
    long fsize(FILE *f)//比较两个文件的大小
    {
        long size;
        fseek(f, 0, SEEK_END); ///将文件指针移动文件结尾
        size = ftell(f);       ///求出当前文件指针距离文件开始的字节数
        return size;
    }
    int command_comp(char **str, int c)
    {
        int flag = 0;
        int i = 3;
        if (i == c)
        {
            return flag;
        }
        for (i; i < c; i++)
        {
            if (strcmp(str[i], "/L") == 0)//显示行号
            {
                flag = flag + 1;
            }
            else if (strcmp(str[i], "/A") == 0)//显示char型
            {
                if (flag == 1 || flag == 0)
                {
                    flag = flag + 2;
                }
            }
            else if (strcmp(str[i], "/D") == 0)//显示十进制
            {
                if (flag == 1 || flag == 0)
                {
                    flag = flag + 4;
                }
            }
            else if (strcmp(str[i], "q") == 0)
            {
            }
            else
            {
                printf("命令行参数有误");
                exit(0);
            }
        }
        return flag;
    }
    void file_comp(char *file1, char *file2, int para)
    {
        FILE *f1;
        FILE *f2;
        char char1, char2;
        int offset = 0;
        int line = 1;
        f1 = fopen(file1, "r");
        f2 = fopen(file2, "r");
        if (fsize(f1) != fsize(f2))//比较文件大小
        {
            printf("文件的大小不同");
        }
        else
        {
            fseek(f1, 0, SEEK_SET);
            fseek(f2, 0, SEEK_SET);
            char1 = fgetc(f1);
            char2 = fgetc(f2);
            offset++;
            if (char1 == '
    ')
            {
                line++;
            }
            while (char1 != EOF)
            {
                if (char1 != char2)
                {
                    if (para == 0)
                    {
                        printf("在offset %d比较错误
    ", offset);
                        printf("file1=%x
    ", char1);
                        printf("file2=%x
    ", char2);
                    }
                    else if (para == 1)
                    {
                        printf("在line %d比较错误
    ", line);
                        printf("file1=%x
    ", char1);
                        printf("file2=%x
    ", char2);
                    }
                    else if (para == 2)
                    {
                        printf("在offset %d比较错误
    ", offset);
                        printf("file1=%c
    ", char1);
                        printf("file2=%c
    ", char2);
                    }
                    else if (para == 4)
                    {
                        printf("在offset %d比较错误
    ", offset);
                        printf("file1=%d
    ", (int)char1);
                        printf("file2=%d
    ", (int)char2);
                    }
                    else if (para == 3)
                    {
                        printf("在line %d比较错误
    ", line);
                        printf("file1=%c
    ", char1);
                        printf("file2=%c
    ", char2);
                    }
                    else
                    {
                        printf("在line %d比较错误
    ", line);
                        printf("file1=%d
    ", char1);
                        printf("file2=%d
    ", char2);
                    }
                }
                char1 = fgetc(f1);
                char2 = fgetc(f2);
                offset++;
                if (char1 == '
    ')
                {
                    line++;
                }
            }
        }
    }
    void comp(int ac, char **av)
    {
        int pa;
        char **command;
        int strLen = 10;
        command = (char **)malloc(sizeof(char *) * strLen); //动态开辟多个char*指针
        for (int i = 0; i < strLen; i++)
        {
            command[i] = (char *)malloc(255);
        }
        command[0] = "0";
        if (ac == 1)
        {
            char *f1;
            char *f2;
            int i = 1;
            char line1[512];
            char line2[512];
            printf("第一个比较文件的名称");
            scanf("%s", command[i]);
            i++;
            printf("第二个比较文件的名称");
            scanf("%s", command[i]);
            while (strcmp(command[i], "q") != 0)
            {
                i++;
                printf("选项");
                scanf("%s", command[i]);
            }
            pa = command_comp(command, i);//分析参数
            file_comp(command[1], command[2], pa);//字符查找
        }
        else
        {
            pa = command_comp(av, ac);
            file_comp(av[1], av[2], pa);
        }
    }
    //fc命令
    void fc(char **argv)
    {
        FILE *fp1;
        FILE *fp2;
        fp1 = fopen(argv[1], "r");
        fp2 = fopen(argv[2], "r");
        char line1[512];
        char line2[512];
        int flag = 0;
        printf("正在比较文件 %s 和 %s
    ", argv[1], argv[2]);
        printf("****%s
    ", argv[1]);
        while (fgets(line1, 512, fp1))//读取文件1的一行,与文件2的每一行相比较
        {
            flag = 0;
            while (fgets(line2, 512, fp2))
            {
                if (strcmp(line1, line2) == 0)
                {
                    flag = 1;
                    break;
                }
            }
            if (flag == 0)
            {
                fputs(line1, stdout);
            }
            fseek(fp2, 0, SEEK_SET);//文件指针指向开头
        }
        fseek(fp1, 0, SEEK_SET);
        printf("****%s
    ", argv[2]);
        while (fgets(line2, 512, fp2))//读取文件2的一行,与文件1的每一行相比较
        {
            flag = 0;
            while (fgets(line1, 512, fp1))
            {
                if (strcmp(line1, line2) == 0)
                {
                    flag = 1;
                    break;
                }
            }
            if (flag == 0)
            {
                fputs(line2, stdout);
            }
            fseek(fp1, 0, SEEK_SET);
        }
        if (flag == 1)
        {
            printf("找不到差异");
        }
    }
    /more命令
    int see_more()
    {
        int c;
        printf("33[7m more? 33[0m"); // : 33[7m     printf反显
        c = getchar();
        if (c != EOF)
        {
            if (c == 'q')//退出
                return 0;
            if (c == 'm')//继续显示
                return 24;
            if (c == '
    ')//显示下一个文件
                return 1;
        }
        return 0;
    }
    void do_more(FILE *fp)
    {
        char line[512];
        int num_of_line = 0;
        int reply;
        //读取每一行赋值给line
        while (fgets(line, 512, fp))
        {
    
            if (num_of_line == 24)
            { //满屏
                reply = see_more();
                if (reply == 0)
                    break;
                num_of_line -= reply;
            }
            if (fputs(line, stdout) == EOF) //打印
                break;
            num_of_line++;
        }
    }
    void more(int argc, char **argv)
    {
        FILE *fp;
        if (argc == 1)
        {
            do_more(stdin);
        }
        else
        {
            while (--argc)
            {
                if ((fp = fopen(*++argv, "r")) != NULL)
                {
                    do_more(fp);
                    fclose(fp);
                }
                else
                    break;
            }
        }
    }
    //help命令
    void help(int argc, char **argv)
    {
        int n = 0;
        if (argc == 1)
        {
            printf("CLS            清除屏幕。
    ");
            printf("COMP           比较两个或两套文件的内容。
    ");
            printf("DATE           显示或设置日期。
    ");
            printf("DOSKEY         编辑命令行、撤回 Windows 命令并创建宏。
    ");
            printf("EXIT           退出 CMD.EXE 程序(命令解释程序)。 
    ");
            printf("FC             比较两个文件或两个文件集并显示它们之间的不同。
    ");
            printf("FIND           在一个或多个文件中搜索一个文本字符串。
    ");
            printf("FINDSTR        在多个文件中搜索字符串。
    ");
            printf("HELP           提供 Windows 命令的帮助信息。
    ");
            printf("MORE           逐屏显示输出。
    ");
            printf("TIME           显示或设置系统时间。
    ");
        }
        else
        {
            if (strcmp(argv[1], "cls") == 0)
            {
                printf("清除屏幕。
    
    CLS
    ");
                n = 1;
            }
            if (strcmp(argv[1], "comp") == 0)
            {
                printf("比较两个文件或两个文件集的内容。
    
    COMP [data1] [data2] [/D] [/A] [/L] [/N=number] [/C] [/OFF[LINE]] [/M]
     data1      指定要比较的第一批文件的位置和名称。
    data2      指定要比较的第二批文件的位置和名称。
    /D         以十进制格式显示差异。
     /A         以 ASCII 字符显示差异。
     /L         显示不同的行数。
    /N=number  只比较每个文件中第一个指定的行数。
    /C         比较文件时 ASCII 字母不区分大小写。
    /OFF[LINE] 不要跳过带有脱机属性集的文件。
    /M         不提示比较更多文件。
    
    要比较文件集,请在 data1 和 data2 参数中使用通配符。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "date") == 0)
            {
                printf("显示或设置日期。
    
    DATE [/T | date]
    
    显示当前日期设置和输入新日期的提示,请键入
    不带参数的 DATE。要保留现有日期,请按 Enter。
    
    如果命令扩展被启用,DATE 命令会支持 /T 开关;
    该开关指示命令只输出当前日期,但不提示输入新日期。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "doskey") == 0)
            {
                printf("编辑命令行,重新调用 Windows 命令,并创建宏。
    
    DOSKEY [/REINSTALL] [/LISTSIZE=size] [/MACROS[:ALL | :exename]]
    [/HISTORY] [/INSERT | /OVERSTRIKE] [/EXENAME=exename] [/MACROFILE=filename]
    [macroname=[text]]
    
     /REINSTALL          安装新的 Doskey 副本。
    /LISTSIZE=size      设置命令历史记录的缓冲区大小。
    /MACROS             显示所有 Doskey 宏。
    /MACROS:ALL         为具有 Doskey 宏的所有可执行文件显示
    所有 Doskey 宏。
    /MACROS:exename     显示指定可执行文件的所有 Doskey 宏。
    /HISTORY            显示存储在内存中的所有命令。
    /INSERT             指定你键入的新文本插入到旧文本中。
    /OVERSTRIKE         指定新文本覆盖旧文本。
    /EXENAME=exename    指定可执行文件。
    /MACROFILE=filename 指定要安装的宏文件。
    macroname           指定你创建的宏的名称。
    text                指定要录制的命令。
    
    上下箭头 重新调用命令;Esc 清除命令行;F7
    显示命令历史记录;Alt+F7 清除
    命令历史记录;F8 搜索命令历史记录;F9 按编号选择命令;Alt+F10 清除宏定义。
    
    以下是 Doskey 宏定义的一些特殊代码:
    $T     命令分隔符。允许一个宏中存在多个命令。
    $1-$9  批处理参数。与批处理程序中的 %1-%9 等同。
    $*     以命令行中命令名称后面的任何内容替换的符号。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "exit") == 0)
            {
                printf("退出 CMD.EXE 程序(命令解释器)或当前批处理脚本。
    
    EXIT [/B] [exitCode]
    
    /B          指定要退出当前批处理脚本而不是 CMD.EXE。如果从一个
     批处理脚本外执行,则会退出 CMD.EXE
    
    exitCode    指定一个数字号码。如果指定了 /B,将 ERRORLEVEL
    设成那个数字。如果退出 CMD.EXE,则用那个数字设置
    过程退出代码。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "fc") == 0)
            {
                printf("比较两个文件或两个文件集并显示它们之间
    的不同
    
    FC [/A] [/C] [/L] [/LBn] [/N] [/OFF[LINE]] [/T] [/U] [/W] [/nnnn]
    [drive1:][path1]filename1 [drive2:][path2]filename2
    FC /B [drive1:][path1]filename1 [drive2:][path2]filename2
    
     /A         只显示每个不同处的第一行和最后一行。
    /B         执行二进制比较。
    /C         不分大小写。
    /L         将文件作为 ASCII 文字比较。
    /LBn       将连续不匹配的最大值设置为指定
    的行数。
    /N         在 ASCII 比较上显示行数。
    /OFF[LINE] 不要跳过带有脱机属性集的文件。
    /T         不要将制表符扩充到空格。
    /U         将文件作为 UNICODE 文本文件比较。
    /W         为了比较而压缩空白(制表符和空格)。
    /nnnn      指定不匹配处后必须连续
    匹配的行数。
    [drive1:][path1]filename1
     指定要比较的第一个文件或第一个文件集。
    [drive2:][path2]filename2
    指定要比较的第二个文件或第二个文件集。
    
    ");
                n = 1;
            }
            if (strcmp(argv[1], "find ") == 0)
            {
                printf("在文件中搜索字符串。
    
    FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "string" [[drive:][path]filename[ ...]]
    
    /V         显示所有未包含指定字符串的行。
    /C         仅显示包含字符串的行数。
    /N         显示行号。
    /I         搜索字符串时忽略大小写。
    /OFF[LINE] 不要跳过具有脱机属性集的文件。
    "string" 指定要搜索的文本字符串。
    [drive:][path]filename
    指定要搜索的文件。
    
    如果没有指定路径,FIND 将搜索在提示符处键入
    的文本或者由另一命令产生的文本。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "findstr") == 0)
            {
                printf("在文件中寻找字符串。
    
    FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] [/F:file]
    [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]]
    strings [[drive:][path]filename[ ...]]
    
    /B         在一行的开始配对模式。
    /E         在一行的结尾配对模式。
    /L         按字使用搜索字符串。
    /R         将搜索字符串作为一般表达式使用。
    /S         在当前目录和所有子目录中搜索匹配文件。
    /I         指定搜索不分大小写。
    /X         打印完全匹配的行。
    /V         只打印不包含匹配的行。
    /N         在匹配的每行前打印行数。
    /M         如果文件含有匹配项,只打印其文件名。
    /O         在每个匹配行前打印字符偏移量。
    /P         忽略有不可打印字符的文件。
    /OFF[LINE] 不跳过带有脱机属性集的文件。
    /A:attr    指定有十六进位数字的颜色属性。请见 "color /?"
    /F:file    从指定文件读文件列表 (/ 代表控制台)。
    /C:string  使用指定字符串作为文字搜索字符串。
    /G:file    从指定的文件获得搜索字符串。 (/ 代表控制台)。
    /D:dir     查找以分号为分隔符的目录列表
    strings    要查找的文字。
    [drive:][path]filename
    指定要查找的文件。
    
    除非参数有 /C 前缀,请使用空格隔开搜索字符串。
    例如: 'FINDSTR "hello there" x.y' 在文件 x.y 中寻找 "hello" 或
    "there"。'FINDSTR /C:"hello there" x.y' 文件 x.y  寻找
    "hello there"。
    
    一般表达式的快速参考:
    .        通配符: 任何字符
    *        重复: 以前字符或类出现零或零以上次数
    ^        行位置: 行的开始
     $        行位置: 行的终点
    [class]  字符类: 任何在字符集中的字符
    [^class] 补字符类: 任何不在字符集中的字符
    [x-y]    范围: 在指定范围内的任何字符
    x       Escape: 元字符 x 的文字用法
    <xyz    字位置: 字的开始
    xyz>    字位置: 字的结束
    
    有关 FINDSTR 常见表达法的详细情况,请见联机命令参考。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "help") == 0)
            {
                printf("提供 Windows 命令的帮助信息。
    HELP [command]
    
     command - 显示该命令的帮助信息。
    ");
                n = 1;
            }
            if (strcmp(argv[1], "more") == 0)
            {
                printf("逐屏显示输出。
    
    MORE [/E [/C] [/P] [/S] [/Tn] [+n]] < [drive:][path]filename
    command-name | MORE [/E [/C] [/P] [/S] [/Tn] [+n]]
    MORE /E [/C] [/P] [/S] [/Tn] [+n] [files]
    
    [drive:][path]filename  指定要逐屏显示的文件。
    
    command-name            指定要显示其输出的命令。
    
    /E      启用扩展功能
    /C      显示页面前先清除屏幕
    /P      扩展 FormFeed 字符
    /S      将多个空白行缩成一行
    /Tn     将制表符扩展为 n 个空格(默认值为 8)
    
    开关可以出现在 MORE 环境变量中。
    +n      从第 n 行开始显示第一个文件
    
    files   要显示的文件列表。使用空格分隔列表中的文件。
    如果已启用扩展功能,则在 -- More -- 提示处 接受下列命令:
    P n 显示下 n 行
    S n 跳过下 n 行
    F 显示下个文件
    Q 退出
    = 显示行号
    ? 显示帮助行
    <space> 显示下一页
    <ret> 显示下一行
    ");
                n = 1;
            }
            if (strcmp(argv[1], "time") == 0)
            {
                printf("显示或设置系统时间。
    
    TIME [/T | time]
    
    显示当前时间设置和输入新时间的提示,请键入
    不带参数的 TIME。要保留现有时间,请按 Enter。
    
    如果命令扩展被启用,TIME 命令会支持 /T 命令行开关;该命令行开关告诉
    命令只输出当前时间,但不提示输入新时间。
    ");
                n = 1;
            }
            if (n == 0)
            {
                printf("帮助工具不支持此命令。请尝试" %s /?"。
    ", argv[1]);
            }
        }
    }
    //time命令
    bool IsLegal(int hour, int minute, int second)//判断时间是否合法的函数
    {
        if (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    void Time(int argc, char **argv)
    {
        int innum = argc;
        time_t timep;
        struct tm *p;
        int hour;
        int minute;
        int second;
        time_t tt;
        const char s[2] = ":";
        char *token;
        //getopt(argc, argv, "ab");
        if (innum == 1)
        {
            time(&timep);
            p = localtime(&timep);//取得当地时间
            printf("当前时间:%02d:%02d:%02d
    ", p->tm_hour, p->tm_min, p->tm_sec);
            while (1)
            {
                printf("输入新时间:");
                scanf("%d:%d:%d", &hour, &minute, &second);
                //转化为tm结构
                p->tm_hour = hour;
                p->tm_min = minute;
                p->tm_sec = second;
                //转化为time_t结构
                tt = mktime(p);
                char ch;
                while ((ch = getchar()) != '
    ' && ch != EOF)
                    ;
                if (IsLegal(hour, minute, second))//判断时间是否合法
                {
                    if (stime(&tt) < 0)//设置时间
                    {
                        printf("系统无法接受输入的时间
    ");
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    printf("系统无法接受输入的时间
    ");
                }
            }
        }
        else if (innum == 2)
        {
            if (strcmp(argv[1], "/t") == 0)
            {
                time(&timep);
                p = localtime(&timep); 
                printf("当前时间:%02d:%02d:%02d
    ", p->tm_hour, p->tm_min, p->tm_sec);
            }
            else if (strcmp(argv[1], "?") == 0)
            {
                printf("显示或设置系统时间。
    ");
                printf("
    TIME [/T| time] 
    ");
                printf("
    显示当前时间设置和输入新时间的提示,请键入不带参数的 TIME。要保留现有时间,请按 Enter。
    ");
                printf("如果命令扩展被启用,TIME 命令会支持 /T 命令行开关;该命令行开关告诉命令只输出当前时间,但不提示输入新时间。
    ");
            }
            else
            {
                printf("%s", argv[1]);
                time(&timep);
                p = localtime(&timep);
                //通过':'将输入字符分割
                if (token = strtok(argv[1], s))
                {
                    hour = atoi(token);
                    if (token = strtok(NULL, s))
                    {
                        minute = atoi(token);
                        if (token = strtok(NULL, s))
                        {
                            second = atoi(token);
                            p->tm_hour = hour;
                            p->tm_min = minute;
                            p->tm_sec = second;
                            tt = mktime(p);
                        }
                        else
                        {
                        }
                    }
                    else
                    {
                    }
                }
                else
                {
                }
                while (1)
                {
                    if (IsLegal(hour, minute, second))
                    {
                        if (stime(&tt) < 0)
                        {
                            printf("系统无法接受输入的时间
    ");
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        printf("系统无法接受输入的时间
    ");
                    }
                    printf("输入新时间:");
                    scanf("%d:%d:%d", &hour, &minute, &second);
                    p->tm_hour = hour;
                    p->tm_min = minute;
                    p->tm_sec = second;
                    tt = mktime(p);
                    char ch;
                    while ((ch = getchar()) != '
    ' && ch != EOF)
                        ;
                }
            }
        }
        else
        {
            printf("系统无法接受输入的时间");
        }
    }
    //date命令
    bool IsLeapYear(int year)//判断日期是否合法的函数
    {
        if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
            return true;
        return false;
    }
    bool DIsLegal(int year, int mon, int day)
    {
        if (year < 0 || mon <= 0 || mon > 12 || day <= 0 || day > 31)
            return false;
        if (1 == mon || 3 == mon || 5 == mon || 7 == mon || 8 == mon || 10 == mon || 12 == mon)
        {
            return true;
        }
        if (IsLeapYear(year))
        {
            if (2 == mon && (28 == day || 30 == day || 31 == day))
                return false;
            return true;
        }
        else
        {
            if (2 == mon && (29 == day || 30 == day || 31 == day))
                return false;
            return true;
        }
    }
    void date(int argc, char **argv)
    {
        char *wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
        time_t timep;
        struct tm *p;
        int innum = argc;
        int year;
        int mon;
        int day;
        struct tm settime;
        struct timeval tv;
        const char s[2] = "-";
        char *token;
        //getopt(argc, argv, "ab");
        if (innum == 1)
        {
            time(&timep);
            p = localtime(&timep); //取得当地时间
            printf("% d/% d/ % d % s
    ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday]);
            while (1)
            {
                printf("输入新日期:<年月日>");
                scanf("%d-%d-%d", &year, &mon, &day);
                //将日期转化为tm结构
                settime.tm_mday = day;
                settime.tm_mon = mon - 1;
                settime.tm_year = year - 1900;
                //通过tm结构转化我timeval结构
                tv.tv_sec = mktime(&settime);
                tv.tv_usec = 0;
                char ch;
                while ((ch = getchar()) != '
    ' && ch != EOF)//清空内存中的字符
                    ;
                if (DIsLegal(year, mon, day))//判断是否合法
                {
                    if (settimeofday(&tv, (struct timezone *)0) < 0)//设置时间
                    {
                        printf("系统无法接受输入的日期
    ");
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    printf("系统无法接受输入的日期
    ");
                }
            }
        }
        else if (innum == 2)
        {
            if (strcmp(argv[1], "/t") == 0)
            {
                time(&timep);
                p = localtime(&timep); //取得当地时间
                printf("% d/% d/ % d % s
    ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday]);
            }
            else if (strcmp(argv[1], "?") == 0)
            {
                printf("显示或设置日期。
    ");
                printf("
    DATE [/T| date] 
    ");
                printf("
    显示当前日期设置和输入新日期的提示,请键入不带参数的DATE。要保留现有日期,请按Enter。
    ");
                printf("如果命令扩展被启用,DATE命令会支持/T开关:该开关指示命令只输出当前日期,但不提示输出新日期。
    ");
            }
            //将输入的字符通过'-'分割
            else
            {
                if (token = strtok(argv[1], s))
                {
                    year = atoi(token);
                    if (token = strtok(NULL, s))
                    {
                        mon = atoi(token);
                        if (token = strtok(NULL, s))
                        {
                            day = atoi(token);
                            settime.tm_mday = day;
                            settime.tm_mon = mon - 1;
                            settime.tm_year = year - 1900;
                            tv.tv_sec = mktime(&settime);
                            tv.tv_usec = 0;
                        }
                        else
                        {
                        }
                    }
                    else
                    {
                    }
                }
                else
                {
                }
                while (1)
                {
                    if (IsLegal(year, mon, day))
                    {
                        if (settimeofday(&tv, (struct timezone *)0) < 0)
                        {
                            printf("系统无法接受输入的日期
    ");
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        printf("系统无法接受输入的日期
    ");
                    }
                    printf("输入新日期:<年月日>");
                    scanf("%d-%d-%d", &year, &mon, &day);
                    settime.tm_mday = day;
                    settime.tm_mon = mon - 1;
                    settime.tm_year = year - 1900;
                    tv.tv_sec = mktime(&settime);
                    tv.tv_usec = 0;
                    char ch;
                    while ((ch = getchar()) != '
    ' && ch != EOF)
                        ;
                }
            }
        }
        else
        {
            printf("系统无法接受输入的日期");
        }
    }
    //cls命令
    void cls(int argc, char **argv)
    {
        if (argc == 1)
        {
            fputs("x1b[2Jx1b[H", stdout);//屏幕控制指令,清除屏幕
        }
        else
        {
            if (strcmp(argv[1], "?") == 0)
            {
                printf("清除屏幕
    ");
                printf("
    CLS
    ");
                printf("
    ");
            }
            else
            {
                fputs("x1b[2Jx1b[H", stdout);
            }
        }
    }
    //exit命令
    void Exit()
    {
        char *f = "kill -9 ";
        char str[10];
        int d = getppid();//获取当前进程的父进程
        sprintf(str, "%d", d);//将d转化为字符串
        //字符串的拼接
        char *command = (char *)malloc(strlen(f) + strlen(str));
        strcpy(command, f);
        strcat(command, str);
        system(command);//执行系统命令
    }
    //主函数
    int main()
    {
        char *input = (char *)malloc(2024);
        int argc;
        int i;
        fputs("x1b[2Jx1b[H", stdout);//清除屏幕
        char buf[80];
        getcwd(buf, sizeof(buf));//获取当前路径
        printf("Microsoft Windows [版本 10.0.18363.535]
    (c) 2019 Microsoft Corporation。保留所有权利。
    ");
        printf("
    ");
        printf("%s>", buf);
        while (gets(input))
        {
            char **argv = (char **)malloc(2024);
            char *temp = (char *)malloc(2024);
            argc = 1;
            i = 0;
            //对命令按空格进行分割,命令存入*argv[]中,命令数存入argc中
            if (strlen(input) != 0)
            {
                char *delim = " ";
                char *p;
                p = strtok(input, delim);
                argv[0] = p;
                while ((p = strtok(NULL, delim)))
                {
                    argv[argc] = p;
                    argc++;
                }
            }
            //判断命令
            if (0 == strcmp(argv[0], "find"))
                find(argc, argv);
            else if (0 == strcmp(argv[0], "findstr"))
                findstr(argv[1], argv[2], argv[3]);
            else if (0 == strcmp(argv[0], "comp"))
                comp(argc, argv);
            else if (0 == strcmp(argv[0], "fc"))
                fc(argv);
            else if (0 == strcmp(argv[0], "date"))
                date(argc, argv);
            else if (0 == strcmp(argv[0], "time"))
                Time(argc, argv);
            else if (0 == strcmp(argv[0], "more"))
                more(argc, argv);
            else if (0 == strcmp(argv[0], "cls"))
                cls(argc, argv);
            else if (0 == strcmp(argv[0], "help"))
                help(argc, argv);
            else if (0 == strcmp(argv[0], "exit"))
                Exit();
            else
            {
                printf("命令行有误");
            }
            //释放内存
            free(argv);
            free(temp);
            printf("%s>", buf);
        }
    }
    
  • 相关阅读:
    关于firstChild,firstElementChild和children
    trim(),正则表达式中文匹配
    Shell之基本用法
    Samba服务部署
    Linux基础(3)
    linux基础(2)
    Linux基础(1)
    网络基础及网络协议
    操作系统简介
    为何要学习计算机基础
  • 原文地址:https://www.cnblogs.com/Qi-Lin/p/12218602.html
Copyright © 2020-2023  润新知