好的!以下是一个完整的 Linux 实战项目教程 —— 《自主 Shell 命令行解释器》。这个项目将引导你一步步构建一个简化版的 Bash Shell,具有基本命令解析、子进程执行、重定向、管道等功能,是学习 Linux 系统编程、进程控制、文件描述符等核心技术的绝佳项目。


🧠 项目概述:自主 Shell 命令行解释器

🎯 项目目标:

实现一个基础版的 Shell,具备如下功能:

功能模块说明
读取命令从命令行读取用户输入
命令解析拆分命令与参数
命令执行创建子进程并执行命令
支持内建命令如 cdexit 等
输入输出重定向支持 > < >>
管道支持支持 `
信号处理Ctrl+C 等中断处理

🧰 开发环境准备

  • 系统:Linux(推荐 Ubuntu/Debian/CentOS)
  • 编译器:gcc
  • 编辑器:vim / VS Code
  • 工具:make(可选)

📂 项目结构(建议)

myshell/
├── main.c              # 主函数,Shell 主循环
├── parser.c/.h         # 命令解析器
├── executor.c/.h       # 命令执行器
├── builtin.c/.h        # 内建命令支持
├── redirect.c/.h       # 重定向功能
├── pipe.c/.h           # 管道功能
└── Makefile

🖥️ 主循环逻辑(main.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "parser.h"
#include "executor.h"

#define MAX_LINE 1024

int main() {
    char line[MAX_LINE];

    while (1) {
        printf("MyShell$ ");
        fflush(stdout);

        if (fgets(line, MAX_LINE, stdin) == NULL) {
            break;
        }

        // 去除换行符
        line[strcspn(line, "\n")] = '\0';

        // 空命令跳过
        if (strlen(line) == 0) continue;

        // 内建命令如 exit
        if (strcmp(line, "exit") == 0) break;

        // 解析和执行
        command_t *cmd = parse_line(line);
        if (cmd) {
            execute_command(cmd);
            free_command(cmd);
        }
    }

    return 0;
}

🧩 命令解析模块(parser.c/.h)

// parser.h
typedef struct {
    char **argv;
    int argc;
    char *input_file;
    char *output_file;
    int append;
    int is_pipe;
    struct command_t *next;
} command_t;

command_t* parse_line(char *line);
void free_command(command_t *cmd);

命令解析应支持:

  • 拆分命令及参数 ls -l /etc
  • 识别重定向 < > >>
  • 管道 ls | grep .c

🔧 命令执行模块(executor.c)

#include "executor.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

void execute_command(command_t *cmd) {
    if (cmd->is_pipe) {
        // 递归执行管道链
        int pipefd[2];
        pipe(pipefd);

        pid_t pid1 = fork();
        if (pid1 == 0) {
            dup2(pipefd[1], STDOUT_FILENO);
            close(pipefd[0]);
            execvp(cmd->argv[0], cmd->argv);
            perror("exec");
            exit(1);
        }

        pid_t pid2 = fork();
        if (pid2 == 0) {
            dup2(pipefd[0], STDIN_FILENO);
            close(pipefd[1]);
            execvp(cmd->next->argv[0], cmd->next->argv);
            perror("exec");
            exit(1);
        }

        close(pipefd[0]);
        close(pipefd[1]);
        wait(NULL);
        wait(NULL);
    } else {
        pid_t pid = fork();
        if (pid == 0) {
            // 重定向
            if (cmd->input_file)
                freopen(cmd->input_file, "r", stdin);
            if (cmd->output_file)
                freopen(cmd->output_file, cmd->append ? "a" : "w", stdout);

            execvp(cmd->argv[0], cmd->argv);
            perror("exec");
            exit(1);
        } else {
            wait(NULL);
        }
    }
}

📥 支持内建命令(builtin.c)

int is_builtin(char *cmd) {
    return strcmp(cmd, "cd") == 0 || strcmp(cmd, "exit") == 0;
}

int execute_builtin(command_t *cmd) {
    if (strcmp(cmd->argv[0], "cd") == 0) {
        return chdir(cmd->argv[1]);
    }
    return -1;
}

🧪 示例运行效果

MyShell$ ls -l > list.txt
MyShell$ cat list.txt | grep .c
parser.c
executor.c

🧠 项目扩展建议

功能实现思路
后台进程 &分析行尾,fork() 后不 wait()
命令历史使用 readline() 库
自动补全借助 libreadline 或 ncurses
多管道解析递归构建命令链表
支持变量添加环境变量解析模块

📘 参考资料


✅ 结语

这个项目不仅锻炼了 C 语言基本功,还深入理解了 Linux 的系统调用、进程控制、文件描述符、重定向和管道机制。适合作为操作系统、系统编程、Linux 实战课程的项目。


📦 如果你需要:

  • 完整源码打包(Makefile + 可运行)
  • 代码注释版 + 中文说明
  • 项目报告文档模板(可用于交作业)

请告诉我,我可以继续为你准备打包资源或文档模板。是否需要?