news 2026/6/8 23:21:55

从零手搓实现 Linux 简易 Shell:内建命令 + 环境变量 + 程序替换全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零手搓实现 Linux 简易 Shell:内建命令 + 环境变量 + 程序替换全解析

从零手搓实现 Linux 简易 Shell
(内建命令 + 环境变量 + 程序替换完整版)

下面我们用 C 语言一步步实现一个极简但功能相对完整的 shell,支持:

  • 读取用户输入、解析命令行(支持参数)
  • 内建命令(cd、exit、pwd、echo、export)
  • 环境变量的读取与修改(支持P A T H 、 PATH、PATHHOME 等)
  • 通过 fork + execvp 执行外部程序
  • 管道(|)的简单支持(单级管道)
  • 前后台进程(&)
  • 基本的信号处理(Ctrl+C 不退出 shell)

目标最终效果(类似 bash 的极简版)

myshell$pwd/home/user myshell$cd/tmp myshell$echo$HOME/home/user myshell$exportMYVAR=hello myshell$echo$MYVARhello myshell$ls-l|greptxt -rw-r--r--1user user1234Feb4txtfile.txt myshell$sleep10&[1]12345myshell$

完整实现代码(约 300 行)

#define_GNU_SOURCE#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/wait.h>#include<sys/types.h>#include<signal.h>#include<errno.h>#include<limits.h>#defineMAX_INPUT1024#defineMAX_ARGS64#defineMAX_PIPES2// 支持一级管道// 全局环境变量表(我们自己维护一份副本)externchar**environ;char**my_environ=NULL;// 前台进程组 pidpid_tfg_pgid=0;// ---------------------- 辅助函数 ----------------------// 字符串 trim 两端空白voidtrim(char*str){char*start=str;char*end;// 跳过开头空白while(*start&&(*start==' '||*start=='\t'||*start=='\n'))start++;if(*start==0){*str='\0';return;}// 找到结尾end=start+strlen(start)-1;while(end>start&&(*end==' '||*end=='\t'||*end=='\n'))end--;*(end+1)='\0';// 移动到开头if(start!=str)memmove(str,start,end-start+2);}// 解析一行输入为参数数组intparse_command(char*input,char**args){intargc=0;char*token;trim(input);if(strlen(input)==0)return0;token=strtok(input," \t\n");while(token&&argc<MAX_ARGS-1){args[argc++]=token;token=strtok(NULL," \t\n");}args[argc]=NULL;returnargc;}// 查找命令是否为内建intis_builtin(constchar*cmd){returnstrcmp(cmd,"cd")==0||strcmp(cmd,"exit")==0||strcmp(cmd,"pwd")==0||strcmp(cmd,"echo")==0||strcmp(cmd,"export")==0||strcmp(cmd,"env")==0;}// 内建命令执行intbuiltin_execute(char**args){if(!args[0])return1;if(strcmp(args[0],"cd")==0){if(!args[1]){chdir(getenv("HOME"));}else{if(chdir(args[1])!=0){perror("cd");}}return1;}if(strcmp(args[0],"exit")==0){exit(0);}if(strcmp(args[0],"pwd")==0){charcwd[PATH_MAX];if(getcwd(cwd,sizeof(cwd))!=NULL){printf("%s\n",cwd);}else{perror("pwd");}return1;}if(strcmp(args[0],"echo")==0){inti=1;while(args[i]){printf("%s",args[i]);if(args[i+1])printf(" ");i++;}printf("\n");return1;}if(strcmp(args[0],"export")==0){if(args[1]){// 支持 export VAR=value 或 export VARchar*eq=strchr(args[1],'=');if(eq){*eq='\0';setenv(args[1],eq+1,1);}else{setenv(args[1],"",1);}}return1;}if(strcmp(args[0],"env")==0){char**env=environ;while(*env){printf("%s\n",*env);env++;}return1;}return0;}// 简单信号处理:Ctrl+C 只影响前台进程voidsigint_handler(intsig){if(fg_pgid>0){kill(-fg_pgid,SIGINT);}// 不退出 shell}// 执行外部命令(支持单级管道)voidexecute_external(char**args,intbackground){intpipefd[2];inthas_pipe=0;// 检测是否有管道for(inti=0;args[i];i++){if(strcmp(args[i],"|")==0){has_pipe=1;args[i]=NULL;// 分割成两个命令char**cmd2=&args[i+1];pipe(pipefd);pid_tpid1=fork();if(pid1==0){// 左命令dup2(pipefd[1],STDOUT_FILENO);close(pipefd[0]);close(pipefd[1]);execvp(args[0],args);perror("execvp left");_exit(1);}pid_tpid2=fork();if(pid2==0){// 右命令dup2(pipefd[0],STDIN_FILENO);close(pipefd[0]);close(pipefd[1]);execvp(cmd2[0],cmd2);perror("execvp right");_exit(1);}close(pipefd[0]);close(pipefd[1]);if(!background){fg_pgid=pid1;waitpid(pid1,NULL,0);waitpid(pid2,NULL,0);fg_pgid=0;}else{printf("[%d] %d\n",1,pid1);}return;}}// 无管道,普通执行pid_tpid=fork();if(pid==0){// 子进程execvp(args[0],args);perror("execvp");_exit(1);}elseif(pid>0){if(!background){fg_pgid=pid;waitpid(pid,NULL,0);fg_pgid=0;}else{printf("[%d] %d\n",1,pid);}}}// 主循环intmain(){charinput[MAX_INPUT];char*args[MAX_ARGS];intargc;// 初始化环境变量副本(可选,setenv/putenv 实际操作的是 environ)// my_environ = environ; // 如果需要自己维护可复制signal(SIGINT,sigint_handler);signal(SIGTSTP,SIG_IGN);// 忽略 Ctrl+Zprintf("欢迎使用 myshell (简易版)\n");printf("支持命令:cd, pwd, echo, export, exit, env, 外部程序, 简单管道, & 后台\n\n");while(1){charcwd[PATH_MAX];getcwd(cwd,sizeof(cwd));printf("myshell:%s$ ",strrchr(cwd,'/')?strrchr(cwd,'/'):cwd);if(!fgets(input,MAX_INPUT,stdin)){printf("\n退出\n");break;}// 去掉换行input[strcspn(input,"\n")]=0;// 解析argc=parse_command(input,args);if(argc==0)continue;intbackground=0;if(argc>1&&strcmp(args[argc-1],"&")==0){background=1;args[--argc]=NULL;}// 内建命令if(is_builtin(args[0])){builtin_execute(args);continue;}// 外部命令或管道execute_external(args,background);}return0;}

编译 & 运行

gcc -o myshell myshell.c ./myshell

功能说明与扩展点

已实现:

  • 内建:cd、exit、pwd、echo、export、env
  • 环境变量读取($PATH 等通过 getenv)
  • 外部程序执行(execvp)
  • 简单单级管道(ls | grep)
  • 后台执行(sleep 100 &)
  • Ctrl+C 只杀前台进程

可以继续扩展的方向

  1. 支持多级管道(需要多个 pipefd 数组 + 循环 fork)
  2. 支持重定向(< > >>)→ 解析时识别符号,dup2
  3. 支持环境变量展开($VAR)→ 在 parse 前替换
  4. 支持历史命令(上下箭头)→ readline 库
  5. 支持 job control(jobs、fg、bg)→ 记录后台进程列表
  6. 支持 alias

小结

这个版本大约 300 行代码,已经包含了 shell 最核心的三大能力:

  • 内建命令(直接执行)
  • 环境变量(getenv / setenv)
  • 程序替换(fork + execvp)

如果你想继续深入某个部分(例如:实现多级管道、重定向、变量展开、job control),可以告诉我,我可以继续补充对应代码和解析。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 16:57:26

制造业五大模式解析:OEM、ODM、OBM、JDM、CMT

目录 一、OEM OEM有个很关键的特点&#xff0c;就是三外一内。 这种模式适合有成熟规模化生产能力。 OEM的优势与劣势&#xff1a; 二、ODM 这里要注意&#xff0c;ODM的设计方案分两种合作形式。 ODM的核心竞争力是工厂的研发设计能力。 ODM适合已经积累了一定产品经验…

作者头像 李华
网站建设 2026/6/5 18:12:21

别再瞎找了!MBA专属AI论文网站 —— 千笔AI

你是否曾为论文选题而焦虑&#xff1f;是否在深夜面对空白文档无从下笔&#xff1f;是否反复修改却仍对表达不满意&#xff1f;MBA论文写作不仅是学术能力的考验&#xff0c;更是时间与精力的双重挑战。从开题报告到文献综述&#xff0c;从框架搭建到查重降噪&#xff0c;每一个…

作者头像 李华
网站建设 2026/5/31 14:36:34

论文查重高?AI检测亮红灯?百考通「降重+降AI」来救场啦!

写论文写到头秃&#xff0c;好不容易搞定初稿&#xff0c;一查重——40%&#xff1f;再用AI检测工具一扫&#xff0c;系统直接标红“高度疑似AI生成”&#xff1f;别慌&#xff01;这年头&#xff0c;认真写也可能“被AI”&#xff0c;引用多一点就被判“重复”&#xff0c;语言…

作者头像 李华
网站建设 2026/5/30 20:11:09

专著第二主编评正高有用吗?

专著第二主编评正高有用吗&#xff1f;专著的第二作者能不能评正高&#xff1f;很多作者想评正高职称&#xff0c;但是不知道专著的第几主编能用&#xff0c;下面淘淘学术来给大家解答这个疑问。 评正高职称&#xff0c;不同省份&#xff0c;不同系列的职称&#xff0c;要求是不…

作者头像 李华
网站建设 2026/6/4 5:09:41

IAB致力于实现可互操作的媒体测量标准化

IAB 于 2 月 2 日 宣布启动“Eidos 项目”&#xff0c;这是一项全行业努力&#xff0c;旨在解决营销人员对高级测量指标的信任差距以及人工智能日益重要的作用。该项目在该行业组织于加利福尼亚州棕榈泉举行的年度领导力会议上推出。 IAB 内部的新部门汇集了来自 30 家营销公司…

作者头像 李华
网站建设 2026/5/24 21:21:37

【小程序毕设全套源码+文档】基于微信小程序的停车位租赁平台设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华