【Linux实验关键代码】用 C/C++构造一个简单的 shell

本文介绍了如何用C/C++实现一个基础的shell,涉及的命令包括sh_cat(合并文件)、sh_cd(目录切换)、sh_echo(打印字符串)等,通过Makefile进行编译和运行。每个命令对应一个C文件,展示了shell的基本功能和文件操作原理。
摘要由CSDN通过智能技术生成

【Linux实验】用 C/C++构造一个简单的 shell


这篇对关键代码做一个提取,如果想了解完整的实验过程, 点这里

一、每一个命令对应一个 C 文件, 有 sh_cat.c, sh_cd.c, sh_echo.c, sh_list.c, sh_ls.c, sh_man.c, sh_mkdir.c, sh_pwd.c, sh_rm.c,sh_wc.c

1、 sh_cat.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int sh_cat(int argc, char *argv[])
{
    if(argc == 2)//灏嗘枃浠朵腑鐨勬墦鍗板埌鏍囧噯杈撳嚭
    {
        FILE *fp;
        if( !(fp = fopen( argv[1], "r" )) )
        {
            printf("No such file or directory!");
            return 1;
        }
        int c;
        while( (c = fgetc(fp) ) != EOF )
        {
            fputc(c,stdout);
        }
        fclose(fp);
    }
    if(argc==3&&strcmp(argv[1],"-n")==0)
    {
        FILE *fp;
        char StrLine[1024];
        if( !(fp = fopen( argv[2], "r" )) )
        {
            printf("No such file or directory!");
            return 1;
        }
        int c;
        int count=1;
        while( fgets(StrLine,1024,fp) != NULL )
        {
            if(count<10)
            {
                printf("   %d  %s",count++,StrLine);
            }
            else if(count<100)
            {
                printf("  %d  %s",count++,StrLine);
            }
            else if(count<1000)
            {
                printf(" %d  %s",count++,StrLine);
            }

        }
        fclose(fp);
    }
    return 0;
}

2、 sh_cd.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int shell_cd(int argc,char *argv[],char **r[])
{
    if(argc==2)
    {
        if(strcmp(argv[1],"-")==0)//切换到上一层目录
        {
            chdir((*r)[1]);//将当前的工作目录改变成以参数path 所指的目录
        }
        else if(strcmp(argv[1],"~")==0)//切换到家目录
        {
            chdir("/home/stu****/");
        }
        else
        {
            if(chdir(argv[1]))
            {
                printf("No such path!\n");
                return 1;
            }
        }
    }
    if(argc==1)
    {
        chdir("/home/stu****/");
    }
    printf("当前工作目录:%s\n",getcwd(NULL,0));
    (*r)[1]=(*r)[0];
    (*r)[0]=getcwd(NULL,0);
    return 0;
}

3、sh_echo.c

#include<stdio.h>
int shell_echo(int argc,char *argv[])
{
    argc--;
    while(argc)
    {
        printf("%s%s",*++argv,(argc > 1)? " ":"");
        argc--;
    }
    printf("\n");
    return 0;
}

4、 sh_list.c

#include<stdio.h>
#include <string.h>

int shell_clist(int argc,char *argv[])
{	
	printf("-------所有功能菜单如下---------\n");
	printf("---------------clist---------------\n");
	printf("------------ls [-a] [-l]------------\n");
	printf("---------------echo-------------\n");
	printf("--------------cat [-n]------------\n");
	printf("--------------mkdir-------------\n");
	printf("--------------rm [-r]------------\n");
	printf("----------------cd---------------\n");
	printf("---------------pwd--------------\n");
	printf("----------wc [-l] [-c] [-w]--------\n");
	printf("---------------history------------\n");
	printf("----------------exit---------------\n");
	printf("-------------help [^]-------------\n");
	return 0;
    
}

5、 sh_ls.c

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

void shell_ls_l(char *file,struct stat st)
{
    char limit[11]={'-','-','-','-','-','-','-','-','-','-','\0'};
    int link=st.st_nlink;
    char user[20];
    char group[20];
    long size=st.st_size;
    char time[50];

    if(S_ISDIR(st.st_mode))
    {
        limit[0]='d';
    }
    if(S_ISBLK(st.st_mode))
    {
        limit[0]='b';
    }
    if(S_ISCHR(st.st_mode))
    {
        limit[0]='c';   
    }
    if(S_ISLNK(st.st_mode))
    {
        limit[0]='l';
    }
    if((S_IRUSR & st.st_mode))
    {
        limit[1]='r';
    }
    if((S_IWUSR & st.st_mode))
    {
        limit[2]='w';
    }
    if((S_IXUSR & st.st_mode))
    {
        limit[3]='x';
    }
    if((S_IRGRP & st.st_mode))
    {
        limit[4]='r';
    }
    if((S_IWGRP & st.st_mode))
    {
        limit[5]='w';
    }
    if((S_IXGRP & st.st_mode))
    {
        limit[6]='x';
    }
    if((S_IROTH & st.st_mode))
    {
        limit[7]='r';
    }
    if((S_IWOTH & st.st_mode))
    {
        limit[8]='w';
    }
    if((S_IXOTH & st.st_mode))
    {
        limit[9]='x';
    }

    strcpy(user,getpwuid(st.st_uid)->pw_name);
    strcpy(group,getgrgid(st.st_gid)->gr_name);
    char swap[50];
    strcpy(swap,ctime(&(st.st_mtime)));
    int i;
    for( i=0;i<(strlen(swap)-1);i++)
    {
        time[i]=swap[i];
    }
    time[i]='\0';

    printf("%s",limit);
    printf("%3d",link);
    printf("%10s",user);
    printf("%10s",group);
    printf("%7ld",size);
    printf("%s",time);
    printf("%s\n",file);


}

int shell_ls(int argc, char *argv[]){
    if(argc==1||argv[1][0]!='-')//*****没有参数的输出
    {
        DIR *dir;
        char str[100];
        char res[1000][100];
        struct dirent *rent;
        if(argc==1)
        {
            dir = opendir(".");
        }
        if(argc==2)
        {
            dir = opendir(argv[argc-1]);
        }
        int cnt = 0;
        while((rent=readdir(dir))!=NULL){
            strcpy(str, rent->d_name);
            if(str[0] == '.')
                continue;
            if(!str)
                continue;
            strcpy(res[cnt++],str);
        }
        for(int i=0; i<cnt; i++)
        {
            printf("%-15s",res[i]);
            if((i+1)%7==0)
            {
                printf("\n");
            }
        }
        printf("\n");
        closedir(dir);
    }
    else if(argc==2||argc==3)//*****有参数的输出**********
    {
        if(strcmp(argv[1],"-l")==0)//********-l参数******
        {
            DIR *dir;
            char str[100];
            char res[1000][100];
            struct dirent *rent;
            if(argc==2)
            {
                dir = opendir(".");
            }
            if(argc==3)
            {
                dir = opendir(argv[argc-1]);
            }
            int cnt = 0;
            while((rent=readdir(dir))!=NULL){
                strcpy(str, rent->d_name);
                if(str[0] == '.')
                    continue;
                if(!str)
                    continue;
                strcpy(res[cnt++],str);
            }
            printf("\n");
            for(int i=0; i<cnt; i++)
            {
                struct stat st;
                char r[100];
                if(argc==2)
                {
                    strcpy(r,"./");
                }
                if(argc==3)
                {
                    strcpy(r,argv[argc-1]);
                }
                
                strcat(r,res[i]);
                stat(r,&st);
                shell_ls_l(res[i],st);
            }
            printf("\n");
            closedir(dir);
            
        }
        if(strcmp(argv[1],"-a")==0)//******-a参数*****
        {
            DIR *dir;
            char str[100];
            char res[1000][100];
            struct dirent *rent;
            if(argc==2)
            {
                dir = opendir(".");
            }
            if(argc==3)
            {
                dir = opendir(argv[argc-1]);
            }
            int cnt = 0;
            while((rent=readdir(dir))!=NULL){
                strcpy(str, rent->d_name);
                if(!str)
                    continue;
                strcpy(res[cnt++],str);
            }
            for(int i=0; i<cnt; i++)
            {
                printf("%-15s",res[i]);
                if((i+1)%7==0)
                {
                    printf("\n");
                }
            }
            printf("\n");
            closedir(dir);
        }
    }
    else
    {

    }
    return 0;
}

6、 sh_man.c

#include<stdio.h>
#include <string.h>

int shell_help(int argc,char *argv[])
{
    if(argc==2)
    {
        if(strcmp(argv[1],"ls")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("ls [-a] [-l] [路径]:用来显示目标目录列表(路径只能是文件夹且路径必须以”/”结尾:例如:ls -l /home/)\n");
            printf("语法:\n");
            printf("ls(选项)(参数)\n");
            printf("[路径]:显示目标目录下的非隐藏文件名\n");
            printf("-a[路径]:显示目标目录下的所有文件名\n");
            printf("-l[路径]:显示目标目录下文件的详细信息\n");

        }
        else if(strcmp(argv[1],"cat")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("cat [-n] [路径]:用来显示文件的内容.\n");
            printf("语法:\n");
            printf("cat(选项)(参数)\n");
            printf("[路径]:显示指定文件的内容\n");
            printf("-n[路径]:显示指定文件的内容,显示的时候在每行行首的位置加上行号\n");
        }
        else if(strcmp(argv[1],"mkdir")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("mkdir [路径]:用来创建文件夹\n");
            printf("语法:\n");
            printf("mkdir (参数)\n");
            printf("[路径]:创建指定路径的文件夹\n");
        }
        else if(strcmp(argv[1],"rm")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("rm -r [路径]:用来删除一个文件或者一个文件夹\n");
            printf("语法:\n");
            printf("rm (选项)(参数)\n");
            printf("[路径]:删除指定路径的文件\n");
            printf("-r [路径]:删除指定路径的文件夹\n");
        }
        else if(strcmp(argv[1],"wc")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("wc -c -l -w [路径]:用来统计一个文件的行数,字符数和单词数\n");
            printf("语法:\n");
            printf("wc (选项)(参数)\n");
            printf("-c [路径]:统计一个文件的字符数\n");
            printf("-l [路径]:统计一个文件的行数\n");
            printf("-w [路径]:统计一个文件的单词数\n");
        }
        else if(strcmp(argv[1],"pwd")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("pwd:用来显示当前工作路径\n");
            printf("语法:\n");
            printf("pwd\n");
            printf("注:该命令无任何参数\n");
        }
        else if(strcmp(argv[1],"echo")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("echo [字符串(可带空格)]:用来直接输出指定的字符串\n");
            printf("语法:\n");
            printf("echo (参数)\n");
            printf("[字符串]:直接打印出指定的字符串\n");
        }
        else if(strcmp(argv[1],"cd")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("cd [路径]|~|-:用来切换工作目录\n");
            printf("语法:\n");
            printf("cd (参数)\n");
            printf("[路径]:切换到指定路径\n");
            printf("-:切换到上一个工作目录\n");
            printf("~:切换到家目录\n");
        }
        else if(strcmp(argv[1],"history")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("history:用来显示最新执行的前10条历史命令\n");
            printf("语法:\n");
            printf("history\n");
            printf("注:该命令无任何参数\n");
        }
        else if(strcmp(argv[1],"clist")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("clist:用来显示所有命令\n");
            printf("语法:\n");
            printf("clist\n");
            printf("注:该命令无任何参数\n");
        }
        else if(strcmp(argv[1],"exit")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("exit:退出Myshell\n");
            printf("语法:\n");
            printf("exit\n");
            printf("注:该命令无任何参数\n");
        }

        else if(strcmp(argv[1],"help")==0)
        {
            printf("%s命令:\n",argv[1]);
            printf("help [命令名]:用来提命令帮助\n");
            printf("语法:\n");
            printf("help (参数)\n");
            printf("[命令名]:显示指定命令名的基本帮助信息\n");
            printf("支持命令:cat,cd,clist,echo,exit,help,ls,mkdir,pwd,rm,wc,history\n");
            
        }
         else
       {
        printf("No such parameter!\n");   
       }
    }
    else
    {
        printf("No such command!\n");   
    }
    
    return 0;
    
}

7、 sh_mkdir.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  
#include <sys/stat.h>
int shell_mkdir(int argc,char *argv[])
{
    if(argc==2)
    {
        mkdir(argv[1],S_IRWXU);
    }
    else
    {
        printf("The name of directory is not correct!\n");
    }
    
    return 0;
}

其余代码实现已上传

二、Make编译和运行
1、makefile

objects = head.h shell_cat.o shell_echo.c shell_ls.o shell_pwd.o shell_rm.o  shell_cd.o shell_help.o shell_mkdir.o shell_wc.o  shell_clist.c Main.c 
****_mysh:$(objects)
	gcc -o ****_mysh $(objects)
%.o: %.c
	gcc -c $<
clean:
	rm *.o
	rm ****_mysh

2、编译运行
编译:直接执行make命令。
运行:./****_mysh

  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

手可摘辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值