[Linux] shell程序编写

一、shell是什么

Linux严格意义上说的是一个操作系统,我们称之为“核心(kernel)“ ,但我们一般用户,不能直接使用kernel。而是通过kernel的“外壳”程序,也就是所谓的shell,来与kernel沟通。

Shell的最简单定义:命令行解释器(command Interpreter)主要包含:

  • 将使用者的命令翻译给核心(kernel)处理。
  • 同时,将核心的处理结果翻译给使用者。

二、简单shell程序编写

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>


#define SIZE 64
#define NUM 1024
#define SEP " "

int lastcode = 0;

char* homepath()
{
   char* home = getenv("HOME");
  if(home)
    return home;
  else 
    return (char*)".";
}

const char* get_user_name()
{
  const char* name = getenv("USER");
  if(name)
    return name;
  else 
    return "none";
}

const char* get_host_name()
{
  const char* hostname = getenv("HOSTNAME");
  if(hostname)
    return hostname;
  else 
    return "none";
}

const char* get_pwd()
{
  const char* pwd = getenv("PWD");
  if(pwd)
    return pwd;
  else 
    return "none";
}


int get_user_command(char* command, int num)
{
  
  printf("[%s@%s %s]# ", get_user_name(), get_host_name(), get_pwd());

  //获取命令行
  char* ret = fgets(command,num,stdin);//无论输入什么,最后一定会输入'\n'(回车)
  command[strlen(command) - 1] = '\0';//所以我们将该命令行数组的最后一个元素改为'\0',不会越界
  
  if(ret == NULL)
  {
    return -1;
  }

  return strlen(command);

}

void command_split(char* in, char* out[])
{

  int argc = 0;
  //2. 分割字符串
  out[argc] = strtok(in, SEP);
  while(out[argc++])
  {
    out[argc] = strtok(NULL,SEP);
  }

  //测试
 // for(int i = 0; out[i]; i++)
//  {
//    printf("%d: %s\n", i, out[i]);
//  }

}

int excute(char* argv[])
{

    //4. 执行命令
    pid_t id = fork();
    {
      if(id < 0)
      {
        return -1;
      }
      else if(id == 0)
      {
        //子进程执行command
       execvp(argv[0],argv); 
        //执行完毕后退出
        exit(1);
      }
      else 
      {
        //父进程等待子进程
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if(rid > 0)
        {
          lastcode = WEXITSTATUS(status);
        }
  
      }

    }
    return 0;
}

  char pwd[1024];
void cd(const char* path)
{
  char tmp[1024];
  
  chdir(path);
  getcwd(tmp,sizeof tmp);
  sprintf(pwd, "PWD=%s",tmp);
  
  putenv(pwd);
}

char myenv[10][100];//10条环境变量,一条容量为100
int v = 0;
//內键命令: 由bash自己执行,类似于自己内部的一个函数
int is_build_in(char* argv[])
{
   if(strcmp(argv[0], "cd") == 0)
   {
      char* path = NULL;
      if(argv[1] == NULL)
        path = homepath(); 
      else 
        path = argv[1];
      cd(path);


      return 1;
   }
   else if(strcmp(argv[0], "export") == 0)
   {
     if(argv[1] == NULL)
        return 1;
     else 
     {
       strcpy(myenv[v++],argv[1]);
       putenv(myenv[v-1]);
     }
   }
   else if(strcmp(argv[0], "echo") == 0)
   {
     if(argv[1] == NULL)
     {
       printf("\n");
       return 1;
     }

     if(*(argv[1]) == '$')
     {
         
         char* val = argv[1]+1;
         if(strcmp(val,"?" ) == 0)
         {
           printf("%d\n",lastcode);
           lastcode = 0;
         }
         else 
         {
           const char* enval = getenv(val);
           if(enval)
             printf("%s\n",enval);
           else 
             printf("\n");
         }
         return 1;

     }
     else 
     {

        printf("%s\n",argv[1]);
        return 1;
     }
   }



 return 0;
}


int main()
{
  while(1)
  {
    lastcode = 0;

    char user_command_line[NUM];
    char* argv[SIZE] = {NULL};


    //1. 打印提示符&&获取用户命令字符串
    int n = get_user_command(user_command_line,sizeof(user_command_line));
    if(n <= 0)
      continue;
    //2. 分割字符串
    command_split(user_command_line, argv);   
   
    //3. 检查是否为內键命令
    n = is_build_in(argv);
    if(n)
      continue;


    //4. 执行命令
    excute(argv);     
  
  }


  return 0;
}

三、makefile文件

mybash:myshell.c
	gcc -o $@ $^ -std=c99

.PHONY:clean 
clean:
	rm -f mybash

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

杯酒问苍天

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

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

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

打赏作者

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

抵扣说明:

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

余额充值