GStreamer 开发手册:从 pipeline 到 caps 协商与性能调优
2026/10/21 8:56:39
【Linux】进程控制(4)自主shell命令行解释器
这一部分的目标是:自己动手写一个极简的 shell,通过这个过程把之前学过的进程控制知识(fork/exec/wait/signal/管道/重定向等)串联起来。
myshell$)&)|、重定向>>><、&&||等while (true) { 打印提示符 读取整行输入 → line 如果 line 为空 或 是 exit/quit → break 解析 line → 切分出命令 + 参数数组 argv[] → 判断是否有 & (后台) if (是内置命令,如 cd exit) { 直接在当前进程执行 } else { pid = fork() if (pid == 0) { // 子进程 execvp(命令, argv) perror("exec失败"); exit(1); } else { // 父进程(shell) if (不是后台) { waitpid(pid, &status, 0); } else { printf("[后台任务] pid = %d\n", pid); // 可以选择不 wait,等它自己结束或用 waitpid(-1,...) 回收 } } } }#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/wait.h>#include<errno.h>#defineMAX_LINE1024#defineMAX_ARGS64intmain(void){charline[MAX_LINE];char*argv[MAX_ARGS];charprompt[]="myshell$ ";while(1){printf("%s",prompt);fflush(stdout);// 读取整行if(!fgets(line,MAX_LINE,stdin)){break;// ctrl+D}// 去掉末尾换行line[strcspn(line,"\n")]=0;// 空行直接继续if(strlen(line)==0)continue;// 退出命令if(strcmp(line,"exit")==0||strcmp(line,"quit")==0){break;}// 解析参数intargc=0;char*token=strtok(line," \t");intbackground=0;while(token){if(strcmp(token,"&")==0){background=1;break;// & 后面不再解析}argv[argc++]=token;token=strtok(NULL," \t");}argv[argc]=NULL;if(argc==0)continue;// 内置命令(先简单处理 exit/cd)if(strcmp(argv[0],"cd")==0){if(argc<2){fprintf(stderr,"cd: 缺少参数\n");}elseif(chdir(argv[1])!=0){perror("chdir");}continue;}// fork + execpid_tpid=fork();if(pid<0){perror("fork");continue;}if(pid==0){// 子进程execvp(argv[0],argv);// 走到这里说明 exec 失败fprintf(stderr,"命令 '%s' 执行失败: %s\n",argv[0],strerror(errno));exit(127);}// 父进程if(!background){intstatus;waitpid(pid,&status,0);}else{printf("[后台作业] pid = %d\n",pid);// 可以不 wait,让它成为孤儿进程,由 init 回收// 或者后续用 waitpid(-1, ...) 非阻塞回收}}printf("\nbye~\n");return0;}gcc -o myshell myshell.c ./myshell然后就可以输入:
myshell$ ls -l myshell$ sleep 10 & myshell$ pwd myshell$ cd /tmp myshell$ exit| 优先级 | 功能 | 关键实现点 | 难度 |
|---|---|---|---|
| ★☆☆ | 支持管道 `cmd1 | cmd2` | fork 两次 + pipe() + dup2 |
| ★★☆ | 支持重定向> >> < | 解析 > >> <,用 open() + dup2 | ★★★ |
| ★★☆ | 回收所有后台进程(waitpid) | 非阻塞 waitpid(-1, &status, WNOHANG) 循环 | ★★ |
| ★★★ | 支持&&` | ` | |
| ★★★ | 实现!历史命令 | 保存历史链表,按 !n 执行 | ★★★ |
| ★★★★ | 支持环境变量展开$HOME | 解析 $ 开头的词,用 getenv() 替换 | ★★★★ |
| ★★★★ | 支持通配符 * ? | 用 glob() 或自己实现匹配 | ★★★★★ |
>和<)strtok_r()(可重入版本)更安全如果你现在想继续做这个项目,可以告诉我你想先实现哪个功能(管道、重定向、后台回收、历史命令……),我可以给你对应的核心代码片段和注意事项。
祝你写出一个属于自己的 shell~