linux学习(自写shell)[11]

打印出提示信息+获取用户键盘输入

在这里插入图片描述
cmd_line[NUM];用来保存完整的命令行

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

#define NUM 1024
char cmd_line[NUM];
//shell
int main()
{
	while(1)
	{
		printf("[root@localhost myshell]# ");
		fflush(stdout);
		//sleep(10);
		memset(cmd_line,'\0',sizeof cmd_line);
		if(fgets(cmd_line,sizeof cmd_line ,stdin) == NULL)
		{
			continue;
		}
		cmd_line[strlen(cmd_line)-1] = '\0';
		
		printf("echo: %s\n",cmd_line);
	}
}

在这里插入图片描述

命令行字符串解析

char *g_argv[SIZE];保存打散后的命令符
strtok第一次调用传入原始字符串,第二次如果还要解析原始字符串则传入空

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

#define NUM 1024
#define SIZE 32
#define SEP " "
char *g_argv[SIZE];
char cmd_line[NUM];
//shell
int main()
{
	while(1)
	{
		printf("[root@localhost myshell]# ");
		fflush(stdout);
		//sleep(10);
		memset(cmd_line,'\0',sizeof cmd_line);
		if(fgets(cmd_line,sizeof cmd_line ,stdin) == NULL)
		{
			continue;
		}
		cmd_line[strlen(cmd_line)-1] = '\0';
		
		printf("echo: %s\n",cmd_line);
		
		g_argv[0] = strtok(cmd_line,SEP);
		int index = 1;
		while(g_argv[index++] = strtok(NULL,SEP));
		for(index = 0;g_argv[index];index++)
			printf("g_argv[%d]:%s\n",index,g_argv[index]);

	}
}

在这里插入图片描述
加上颜色和部分连续命令

if(strcmp(g_argv[0], "ls") == 0)
        {
            g_argv[index++] = "--color=auto";
        }
        if(strcmp(g_argv[0], "ll") == 0)
        {
            g_argv[0] = "ls";
            g_argv[index++] = "-l";
            g_argv[index++] = "--color=auto";
        }

TODO内置命令

变化路径
在这里插入图片描述

fork()

在这里插入图片描述

全部代码

myshell.c

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

#define NUM 1024
#define SIZE 32
#define SEP " "

//保存完整的命令行字符串
char cmd_line[NUM];
//保存打散之后的命令行字符串
char *g_argv[SIZE];

// shell 运行原理 : 通过让子进程执行命令,父进程等待&&解析命令
int main()
{
    //0. 命令行解释器,一定是一个常驻内存的进程,不退出
    while(1)
    {
        //1. 打印出提示信息 [whb@localhost myshell]# 
        printf("[root@localhost myshell]# ");
        fflush(stdout);
        memset(cmd_line, '\0', sizeof cmd_line);
        //2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
        if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
        {
            continue;
        }
        cmd_line[strlen(cmd_line)-1] = '\0';
        //"ls -a -l -i\n\0"
        //printf("echo: %s\n", cmd_line);
        //3. 命令行字符串解析:"ls -a -l -i" -> "ls" "-a" "-i"
        g_argv[0] = strtok(cmd_line, SEP); //第一次调用,要传入原始字符串
        int index = 1;
        if(strcmp(g_argv[0], "ls") == 0)
        {
            g_argv[index++] = "--color=auto";
        }
        if(strcmp(g_argv[0], "ll") == 0)
        {
            g_argv[0] = "ls";
            g_argv[index++] = "-l";
            g_argv[index++] = "--color=auto";
        }
        //?
        while(g_argv[index++] = strtok(NULL, SEP)); //第二次,如果还要解析原始字符串,传入NULL

        //for debug
        //for(index = 0; g_argv[index]; index++)
        //    printf("g_argv[%d]: %s\n", index, g_argv[index]);
        //4. TODO,内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令
        //内建命令本质其实就是shell中的一个函数调用
        if(strcmp(g_argv[0], "cd") == 0) //not child execute, father execute
        {
            if(g_argv[1] != NULL) chdir(g_argv[1]); //cd path, cd ..

            continue;
        }
        //5. fork()
        pid_t id = fork();
        if(id == 0) //child
        {
            printf("下面功能让子进程进行的\n");
            //cd cmd , current child path
            execvp(g_argv[0], g_argv); // ls -a -l -i
            exit(1);
        }
        //father
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));
    }
}


Makefile

```cpp
myshell:myshell.c
	gcc -o $@ $^

.PHONY:clean
clean:
	rm -f myshell


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值