news 2026/4/18 1:06:35

从零手搓实现 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/4/18 4:40:08

Wordtune

1. 它是什么Wordtune 是一个基于人工智能的写作辅助工具。它的核心功能是理解用户输入的句子或段落&#xff0c;并提供多种不同的改写方式和表达建议。可以将它想象成一个时刻在线的文字编辑伙伴&#xff0c;专门帮助调整句子的语气、清晰度和流畅性&#xff0c;而不是仅仅纠正…

作者头像 李华
网站建设 2026/4/18 6:30:10

AI写论文的法宝!4款AI论文写作工具,助力高质量论文产出!

四款AI论文写作工具实测推荐 撰写期刊论文、毕业论文或者职称论文的时候&#xff0c;许多学者都会遇到各种各样的难题。对于需要手动撰写的论文&#xff0c;面对成堆的相关文献&#xff0c;无异于在沙滩上寻找珍珠&#xff1b;严格的格式要求常常让人感到无比压力&#xff0c;…

作者头像 李华
网站建设 2026/3/28 7:37:15

AI写论文必备!4款AI论文写作神器,高效完成毕业论文不是梦!

学术论文写作的AI工具实测推荐 在撰写期刊论文、毕业论文或职称论文的过程中&#xff0c;学术研究者经常会遇到不少挑战。面对海量的文献资料&#xff0c;有时查找相关信息就像在大海中捞针&#xff1b;而严格的格式要求常常让写作者感到压力山大&#xff1b;不断的修改过程又…

作者头像 李华
网站建设 2026/4/18 6:26:36

【小程序毕设源码分享】基于springboot+小程序的个性化推荐的外卖点餐系统的设计与实现(程序+文档+代码讲解+一条龙定制)

发布文章 【小程序毕设全套源码文档】基于微信小程序的个性化推荐的外卖点餐系统设计与实现(丰富项目远程调试讲解定制) 56/100 bishe638 未选择任何文件 博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈…

作者头像 李华
网站建设 2026/4/15 11:16:10

‌暗物质探测:图神经网络在粒子对撞异常事件的识别工具‌

当软件测试遇上宇宙探索 在软件测试领域&#xff0c;我们每天都在与异常事件“斗智斗勇”——从代码缺陷到系统崩溃&#xff0c;检测和修复这些问题是核心职责。有趣的是&#xff0c;高能物理学家也在进行类似的“测试”&#xff1a;他们用粒子对撞机模拟宇宙事件&#xff0c;…

作者头像 李华
网站建设 2026/4/10 17:18:34

Java基于web的医疗设备管理系统毕业论文+PPT(附源代码+演示视频)

文章目录一、项目简介1.1 运行视频1.2 &#x1f680; 项目技术栈1.3 ✅ 环境要求说明1.4 包含的文件列表前台运行截图后台运行截图项目部署源码下载一、项目简介 项目基于SpringBoot框架&#xff0c;前后端分离架构&#xff0c;后端为SpringBoot前端Vue。基于Web的医疗设备管理…

作者头像 李华