当前位置:首页 > 系统教程 > 正文

Linux实战:从零手写一个简易shell(myshell)

Linux实战:从零手写一个简易shell(myshell)

Linux shell 是每个运维和开发者的必备工具,但你知道它背后是如何工作的吗?本教程将带你用C语言实现一个属于自己的 myshell,深入理解 进程管理 和命令行解释器的核心原理。这是一个非常适合初学者的 简单shell实现 项目,小白也能轻松跟上!

1. 什么是Shell?

Shell 是Linux系统的用户接口,它接收用户输入的命令,并调用操作系统内核执行。常见的Shell有bash、zsh等。今天我们要实现的 myshell 将具备最基本的命令执行功能(例如 lspwd),并展示 进程管理 的核心 —— fork()exec() 家族函数。

2. 实现思路与准备

我们将分步完成:

  • 打印提示符,等待用户输入
  • 解析输入的命令和参数
  • 创建子进程执行命令
  • 父进程等待子进程结束
  • 处理简单的内置命令(如 exit

首先创建源文件 myshell.c,并用你喜欢的编辑器打开。

Linux实战:从零手写一个简易shell(myshell) Linux shell  简单shell实现 myshell 进程管理 第1张

3. 编写代码框架

下面是完整的 myshell.c 代码,每一步都有详细注释:

    #include #include #include #include #include #define MAX_INPUT 1024#define MAX_ARGS 64// 函数声明void print_prompt();int read_input(char *buffer);int parse_input(char *buffer, char **args);int execute_command(char **args);int main() {    char input[MAX_INPUT];    char *args[MAX_ARGS];    int should_run = 1;    while (should_run) {        print_prompt();        if (!read_input(input)) continue;   // 空输入则继续        int arg_count = parse_input(input, args);        if (arg_count == 0) continue;        // 简单内置命令:exit        if (strcmp(args[0], "exit") == 0) {            printf("Goodbye!");            should_run = 0;            continue;        }        // 执行外部命令        execute_command(args);    }    return 0;}void print_prompt() {    printf("myshell> ");    fflush(stdout);}int read_input(char *buffer) {    if (fgets(buffer, MAX_INPUT, stdin) == NULL) {        return 0;   // EOF    }    // 去除末尾的换行符    buffer[strcspn(buffer, "")] = "�";    return 1;}int parse_input(char *buffer, char **args) {    int count = 0;    char *token = strtok(buffer, " 	");    while (token != NULL && count < MAX_ARGS - 1) {        args[count++] = token;        token = strtok(NULL, " 	");    }    args[count] = NULL;    return count;}int execute_command(char **args) {    pid_t pid = fork();    if (pid < 0) {        perror("fork failed");        return -1;    } else if (pid == 0) {        // 子进程        if (execvp(args[0], args) == -1) {            perror("command not found");        }        exit(EXIT_FAILURE);    } else {        // 父进程等待子进程结束        int status;        waitpid(pid, &status, 0);    }    return 0;}  

以上代码展示了 进程管理 的经典模式:父进程 fork() 出子进程,子进程调用 execvp() 加载用户命令,父进程用 waitpid() 回收子进程资源。这正是 Linux shell 最核心的机制。

4. 代码详解

4.1 主循环与输入

main() 函数中的 while 循环构成了Shell的主干。每次循环打印提示符 myshell> ,然后读取用户输入。使用 fgets() 确保不会缓冲区溢出。

4.2 解析命令

parse_input()strtok() 将输入字符串按空格或制表符分割成命令和参数,并以NULL结尾,方便 execvp() 直接使用。

4.3 执行命令

execute_command() 中调用 fork() 创建新进程。子进程执行 execvp(),如果失败则打印错误;父进程调用 waitpid() 等待子进程结束,避免产生僵尸进程。这就是 简单shell实现 的精髓。

5. 编译与测试

在终端中执行以下命令编译:

    gcc -o myshell myshell.c  

然后运行 ./myshell,你将看到:

    myshell> pwd/home/user/projectmyshell> ls -l(显示当前目录文件)myshell> exitGoodbye!  

如果输入的命令不存在,会提示 command not found。至此,一个迷你的 myshell 就诞生了!

6. 扩展与思考

当前的实现非常基础,你可以尝试添加更多功能:

  • 支持输入输出重定向(><
  • 实现管道(|
  • 增加内置命令 cd(需要调用 chdir()
  • 支持后台运行(&

通过这个项目,你已经亲手揭开了 Linux shell 的神秘面纱,掌握了 进程管理 的基本操作。继续探索,你会发现更多操作系统的奥秘!

—— 教程结束,希望你喜欢这次 简单shell实现 之旅 ——