结合之前学习的内容写一个简单的shell命令行解释器

 

目录

实现思路

内建命令如何实现


 

实现思路

循环以下过程:

1. 获取命令行

2. 解析命令行

3. 建立一个子进程(fork)

4. 替换子进程(execvp)

5. 父进程等待子进程退出(wait)

实现代码:

int main()
{
  while(1)
  {
    printf("[用户名@主机名 路径]$ ");
    fflush(stdout);//刷新缓冲区
    ssize_t n = read(0,lineCommand,sizeof(lineCommand));//将stdin的数据读到lineCommand变量中
    assert(n != -1);
    lineCommand[strlen(lineCommand)-1]=0;//去掉输入命令时按的\n
    
    //输入指令时会以空格隔开,利用这点提取指令和参数,存在指针数组中
    int i = 0;
    myargv[i++] = strtok(lineCommand," ");
    while(myargv[i++] = strtok(NULL," "));

    pid_t id = fork();
    if(id < 0)
    {
      printf("fork fail");
      exit(1);
    }

    if(id == 0)
    {//child
    
      execvp(myargv[0],myargv);
      exit(1);
    
    }
    waitpid(id,NULL,0);
  }
  return 0;
}

内建命令如何实现

运行上面的代码可以发现cd到上级目录后查看当前路径没有变化,为什么会这样?

首先来了解一下什么是当前路径:

运行一段代码

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

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        while(1)
        {
            printf("我是子进程,pid: %d\n",getpid());
            sleep(2);
        }
    }
    return 0;
}

 查进程文件

当前路径本质就是进程的工作目录

 调用chdir函数可以改变进程的工作目录

 修改一下代码

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

int main()
{
    chdir("/home/wcl");//修改工作目录
    pid_t id = fork();
    if(id == 0)
    {
        while(1)
        {
            printf("我是子进程,pid: %d\n",getpid());
            sleep(2);
        }
    }
    return 0;
}

修改成功 

回到最初的问题,为什么我们自己写的myshell,cd的时候,路径没有变化呢?原因是:

fork() --->子进程 执行的 cd---> 子进程有自己的工作目录---> 更改的是子进程的目录! --->子进程执行完毕 ---> 继续用的是父进程,即myshell!

将myshell代码修改一下即可实现cd命令

#include <stdlib.h>
#include<assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NUM 1024
char lineCommand[NUM];
char *myargv[1024];
char buf[1024];
char *route[1024];

int main()
{
  while(1)
  {
    //目前水平不知道怎么获取路径,用了一个不怎么高明的方法,但是总归能解决问题。
    int cnt = 0;
    getcwd(buf,sizeof(buf));
    route[cnt++] = strtok(buf,"/");
    while(route[cnt++] = strtok(NULL,"/"));
    
    printf("[%s@%s %s]$ ",getenv("USER"),getenv("HOSTNAME"),route[cnt-2]);
    fflush(stdout);//刷新缓冲区

    memset(lineCommand,0,sizeof(lineCommand));
    ssize_t n = read(0,lineCommand,sizeof(lineCommand));//将stdin的数据读到lineCommand变量中
    assert(n != -1);
    lineCommand[strlen(lineCommand)-1]=0;//去掉输入命令时按的\n
    
    //输入指令时会以空格隔开,利用这点提取指令和参数,存在指针数组中
    int i = 0;
    myargv[i++] = strtok(lineCommand," ");
    while(myargv[i++] = strtok(NULL," "));

    if(myargv[0] != NULL && strcmp(myargv[0],"cd") == 0)
    {
      if(myargv[1] != NULL) chdir(myargv[1]);//内建命令
      continue;
    }

    pid_t id = fork();
    if(id < 0)
    {
      printf("fork fail");
      exit(1);
    }

    if(id == 0)
    {//child
    
      execvp(myargv[0],myargv);
      exit(1);
    
    }
    waitpid(id,NULL,0);
  }
  return 0;
}

• 如果是cd命令,不需要创建子进程,让she11自己执行对应的命令,本质就是执行系统接口

• 像这种不需要让我们的子进程来执行,而是让she11自已执行的命令叫做 内建/内置命令

编译运行看看效果

myshell一眼看上去和系统的shell没什么区别,不过myshell没有配色规则。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值