一个简单的Linux Shell

程序描述

此程序实现了一个简单的Linux壳,支持输入各类命令参数,并为其创建进程并等待子进程结束。

程序实现思路

这个程序大致可以分为两部分 ,其一为获取用户输入的命令及参数并将其整理为数组,其二为创建子进程并调用execvp将子进程用于执行输入的命令,其中拆分得到的用户输入的字符串为难点

重难点解析

接收用户输入

接收用户的命令输入并不能简单的用scanf来实现,因为单纯的scsnf是不支持空格和tab的,而gets方法虽然能够接收空格却不被Linux系统所支持,所以我们选择了Linux所支持的gets的替代品——fgets。(更好的方法是scanf(“%[^\n]”, buffer);定义收到换行符才结束,其余的都接收。)

函数原型

char *fgets(char *buf, int bufsize, FILE *stream);
其中buf代表用于接收用户输入的字符串指针,bufsize代表接收的数据大小,stream用于指定读取流。

代码演示
fgets(cmdline,CMDLEN,stdin);

CMDLEN是我宏定义的cmdline的长度,stdin代表从键盘读取。

注意

fgets方法接收到字符串的最后带有换行符\n

字符串解析

接收到用户输入的字符串后需要根据空格将其解析,在这里我们用strtok方法来实现。

使用示例
char *args[PARAM];
for(i=0;i<PARAM;i++){
    args[i]=(char*)malloc(CMDLEN);
}
char delims[]=" ";
args[0]=strtok(cmdline,delims);
//printf("%s",arg[0]);
for(i=1;i<PARAM;i++){
    args[i]=strtok(NULL,delims);
    if(!args[i]){
        break;
    }
}

其中PARAM是我宏定义的最多参数个数,首先为char*开辟空间(一定要开辟不然无法使用),然后将分隔符存入一个字符数组中,我们要用空格分割所以存的是空格。strtok第一次使用要加第一个参数为需要分割的字符串指针,以后使用则设为NULL。每次返回一段字符,最后结束返回NULL(恰好execvp最后一个参数需要为NULL,所以很方便)
戳这里了解更多strtok的知识

创建子进程

pid_t pid;
pid=fork();
if(pid==0){
    if(execvp(args[0], args)<0){
        printf("执行失败, errno is: %d\n", errno); 
    }
    //errno 2 代表文件找不到,如果没有去掉fgets读回来的换行符\n就会发生这种错误;
    //errno 14 代表参数最后不是空指针,注意要直接赋值为NULL而不是"NULL""";
    exit(0);
}
else{
    wait(NULL);
}

完整代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h> 
#define CMDLEN 100 //命令参数最多接收100个字符
#define PARAM 10  //最多支持参数个数

/**
 * [deletEnter description]
 * 用于删除字符串后面的换行符
 * @param str [description]
 */
void deletEnter(char *str){
    int i=0;
    while(1){
        if(str[i]=='\n'){ 
            str[i]='\0'; //查到有换行符就换成\0结束
            break;
        }else if(str[i]=='\0'){
            break;
        }
        i++;
    }
}

int main(){
    char cmdline[CMDLEN];
    char *args[PARAM];
    while(1){
        printf("[tyshell]# ");
        fflush(stdout);
        fgets(cmdline,CMDLEN,stdin);//不能用svanf(收不到空格)和gets(linux不支持)
        /**
         * 如果接收到exitq就退出,否则就解析命令创建子进程执行
         */
        if(strcmp(cmdline,"exit\n")==0){
            //fgets读取到的内容末尾有换行符故判断结束需要加上\n
            return 0;
        }else{
            int i=0;
            /**
             * 调用方法删去字符串最后的换行符
             */
            deletEnter(cmdline);
            //检验接收是否有误
            //printf("arglen=%d\n",arglen);
            //printf("%s\n",cmdline);
            //char *arg[arglen+1];  
            /**
             * 指针初始化
             */
            for(i=0;i<PARAM;i++){
                args[i]=(char*)malloc(CMDLEN);
            }
            /**
             * 使用strtok解析,拆分字符串,用法如下
             */
            char delims[]={" "};
            args[0]=strtok(cmdline,delims);
            //printf("%s",arg[0]);
            for(i=1;i<PARAM;i++){
                args[i]=strtok(NULL,delims);
                if(!args[i]){
                    break;
                }
                //printf("%s",arg[i]);
            }

            //开始多线程的执行
            pid_t pid;
            pid=fork();
            if(pid==0){
                if(execvp(args[0], args)<0){
                    printf("执行失败, errno is: %d\n", errno); 
                }
                //errno 2 代表文件找不到,如果没有去掉fgets读回来的换行符\n就会发生这种错误;
                //errno 14 代表参数最后不是空指针,注意要直接赋值为NULL而不是"NULL""";
                exit(0);
            }
            else{
                wait(NULL);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值