好的!以下是一个完整的 Linux 实战项目教程 —— 《自主 Shell 命令行解释器》。这个项目将引导你一步步构建一个简化版的 Bash Shell,具有基本命令解析、子进程执行、重定向、管道等功能,是学习 Linux 系统编程、进程控制、文件描述符等核心技术的绝佳项目。
🧠 项目概述:自主 Shell 命令行解释器
🎯 项目目标:
实现一个基础版的 Shell,具备如下功能:
功能模块 | 说明 |
---|---|
读取命令 | 从命令行读取用户输入 |
命令解析 | 拆分命令与参数 |
命令执行 | 创建子进程并执行命令 |
支持内建命令 | 如 cd 、exit 等 |
输入输出重定向 | 支持 > < >> |
管道支持 | 支持 ` |
信号处理 | 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 |
多管道解析 | 递归构建命令链表 |
支持变量 | 添加环境变量解析模块 |
📘 参考资料
- 《Advanced Programming in the UNIX Environment》
- Linux man pages:
man execvp
,man fork
,man dup2
- GitHub 示例项目:
https://github.com/ohmybash/simple-shell
https://github.com/brendanzab/shell
✅ 结语
这个项目不仅锻炼了 C 语言基本功,还深入理解了 Linux 的系统调用、进程控制、文件描述符、重定向和管道机制。适合作为操作系统、系统编程、Linux 实战课程的项目。
📦 如果你需要:
- 完整源码打包(Makefile + 可运行)
- 代码注释版 + 中文说明
- 项目报告文档模板(可用于交作业)
请告诉我,我可以继续为你准备打包资源或文档模板。是否需要?
发表回复