0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux实现简易的Shell命令行解释器

dyquk4xk2p3d 来源:入门小站 作者:入门小站 2023-03-30 10:00 次阅读

一、前言

来制作一个简易的 [Shell 命令]行解释器。

首先这是与 Shell 的互动::

ae1c7a54-ce8a-11ed-bfe3-dac502259ad0.png

用下图的[时间轴]来表示事件的发生次序。其中时间从> > 左向右。shell 由标识为 sh 的方块代表,它随着时间的流逝从左向右移动。shell 从用户读入字符串 "ls"。shell 建立一个新的进程,然后在那个进程中运行 ls 程序并等待那个进程结束。

ae3edf4a-ce8a-11ed-bfe3-dac502259ad0.png

然后 shell 读取新的一行输入,建立一个新的进程,在这个进程中运行程序 并等待这个进程结束。所以要写一个 shell,需要循环以下过程:

1. 获取命令行

2. 解析命令行

3. 建立一个子进程(fork)

4. 替换子进程(execvp)

5. 父进程等待子进程退出(wait)

二、准备工作

1.输出提示符

ae709f44-ce8a-11ed-bfe3-dac502259ad0.png

这里的提示字符为用户名 @主机名 当前路径# 直接打印出来作为提示所用

printf("用户名@主机名当前路径#");

这里没有 n,会有缓冲区的问题,类似于我们之前所说的进度条所遇到的问题,可以用 fflush(stdout) 刷新缓冲区。

2. 输入和获取命令

输入

我们需要输入一连串命令,其中可能出现空格,所以不能使用 gets 函数,需要用到 fgets 函数,同时,可以定义一个 lineCommand[NUM] 数组

#defineNUM1024
charlineCommand[NUM];
char*s=fgets(lineCommand,sizeof(lineCommand)-1,stdin);
assert(s!=NULL);

但是打印的时候却多换了一行,这是我们把 n 也读取到了,直接进行处理即可, 清除最后一个 n

lineCommand[strlen(lineCommand)-1]=0;

可以通过打印看看效果和测试是否有 BUG

printf("test:%s
",lineCommand);
ae85b9c4-ce8a-11ed-bfe3-dac502259ad0.png

获取

输入之后,我们自然需要去进行获取,我们需要分割命令行,这个地方用 strtok。把字符串切割成若干个子串:
strtok: 第一次直接传递参数,第二次则必须传 NULL。且在最终 strtok 会返回 NULL。

ae99dc06-ce8a-11ed-bfe3-dac502259ad0.pngaec2e524-ce8a-11ed-bfe3-dac502259ad0.png

3.shell 运行原理

同时,在理解一下 shell 的运行原理:shell 内部提取命令行做分析,然后调用 exec. shell 执行命令必须通过创建子进程,如果不创建子进程会把我们所有的 shell 全部替换,所以执行命令时一般磁盘上的程序必须创建子进程。

4. 内建命令

我们在运行自己写的 shell 的时候,发现输入 cd … 输入 cd path 等命令时发现路径并没有改变!

aee97ca2-ce8a-11ed-bfe3-dac502259ad0.png

没有发生改变是因为自己写的 shell 执行很多命令都要 fork() 创建子进程,让子进程执行的 cd,子进程有自己的工作目录,所以更改的子进程的目录,子进程执行完毕,继续用的是父进程,既 shell,并没有影响父进程,所以并没有改变。

对于 cd, 我们可以采用内建命令:不需要创建子进程执行,让 shell 自己执行命令,称为内建命令。本质就是执行系统接口,我们可以调用一个系统接口 chdir,可解决上述问题:

aefa5928-ce8a-11ed-bfe3-dac502259ad0.png
af185b26-ce8a-11ed-bfe3-dac502259ad0.png

5. 替换

采用 execvp 进行替换进程

pid_tid=fork();
assert(id!=-1);
if(id==0)
{
execvp(myargv[0],myargv);
exit(1);
}

三、整体代码

 #include
#include
#include
#include
#include
#include
#include
#defineNUM1024
#defineOPT_NUM64
charlineCommand[NUM];
char*myargv[OPT_NUM];//指针数组
intlastcode=0;
intlastsig=0;
intmain()
{
while(1)
{
//1.输出提示符
printf("lj@VM-8-2-centos当前路径#");
fflush(stdout);
//2.获取用户输入的命令,输入的时候,用户最后还输入了

char*s=fgets(lineCommand,sizeof(lineCommand)-1,stdin);
assert(s!=NULL);
(void)s;//避免Linux认为s变量未使用,导致警告
//清除最后一个
;例如:abcd

lineCommand[strlen(lineCommand)-1]=0;
//printf("test:%s
",lineCommand);
//"ls-a-l-i"-->字符串分割-->"ls""-a""-l""-i"
myargv[0]=strtok(lineCommand,"");
inti=1;
if(myargv[0]!=NULL&&(strcmp(myargv[0],"ls")==0))
{
myargv[i++]=(char*)"--color=auto";
}
//如果没有子串了,strtok会返回NULL,即myargv[end]=NULL
while(myargv[i++]=strtok(NULL,""));
//如果是cd命令,不需要创建子进程,让shell自己执行对应的命令,本质就是执行系统接口
//像这种不需要让我们的子进程来执行,而是让shell自己执行的命令—内建命令
//其中echo是一个自建命令
if(myargv[0]!=NULL&&(strcmp(myargv[0],"cd")==0))
{
if(myargv[1]!=NULL)chdir(myargv[1]);
continue;
}
if(myargv[0]!=NULL&&myargv[1]!=NULL&&(strcmp(myargv[0],"echo")==0))
{
if(strcmp(myargv[1],"$?")==0)
{
printf("%d,%d
",lastcode,lastsig);
}
else
{
printf("%s
",myargv[i]);
}
continue;
}
//利用条件编译测试是否成功
#ifdefDEBUG
for(inti=0;myargv[i];++i)
{
printf("myargv[%d]:%s
",i,myargv[i]);
}
#endif
//执行命令
pid_tid=fork();
assert(id!=-1);
if(id==0)
{
execvp(myargv[0],myargv);
exit(1);
}
intstatus=0;
pid_tret=waitpid(id,&status,0);
assert(ret>0);
(void)ret;
lastcode=(status>>8)&0xFF;
lastsig=status&0x7F;
}
return0;
}
af335782-ce8a-11ed-bfe3-dac502259ad0.png

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11217

    浏览量

    208822
  • 命令行
    +关注

    关注

    0

    文章

    77

    浏览量

    10380
  • Shell
    +关注

    关注

    1

    文章

    363

    浏览量

    23274
  • 进程
    +关注

    关注

    0

    文章

    201

    浏览量

    13942
  • 解释器
    +关注

    关注

    0

    文章

    103

    浏览量

    6491

原文标题:Linux 实现简易的 Shell 命令行解释器

文章出处:【微信号:良许Linux,微信公众号:良许Linux】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    在STM32实现命令行

    工作中的开发环境都是基于linux命令行交互,作为命令行的重度使用者,玩单片机也要使用命令行工具,百度了一些命令行工具,有几个不错的开源 c
    发表于 12-09 11:32 2255次阅读

    Linux图形界面的原理与构成和Linux命令行和vi编辑的使用手册

    本文档的主要内容详细介绍的是Linux基础教案主要内容是:(1) 了解Linux图形界面的原理与构成;(2)掌握Linux命令行操作,包括:命令行
    发表于 10-16 14:49 6次下载
    <b class='flag-5'>Linux</b>图形界面的原理与构成和<b class='flag-5'>Linux</b><b class='flag-5'>命令行</b>和vi编辑<b class='flag-5'>器</b>的使用手册

    Linux桌面系统初级教程之Shell命令行操作的资料概述

    Linux shell指的是一种程序,有了它,用户就能通过键盘输入指令来操作计算机了。Shell会执行用户输入的命令,并且在显示上显示执行
    发表于 11-09 17:42 18次下载
    <b class='flag-5'>Linux</b>桌面系统初级教程之<b class='flag-5'>Shell</b><b class='flag-5'>命令行</b>操作的资料概述

    Linux 命令行教程好书推荐

    今天跟大家推荐个 Linux 命令行教程:《The Linux Command Line》,中文译名:《Linux 命令行大全》。 该书作者
    的头像 发表于 02-14 09:25 1448次阅读

    mini shell命令行调试工具(单片机、c语言)

    @mini shell命令行调试工具介绍Mini shell 命令行调试工具(单片机、c语言)Mini shell是一个特别适合低内存的单片
    发表于 11-29 10:21 9次下载
    mini <b class='flag-5'>shell</b><b class='flag-5'>命令行</b>调试工具(单片机、c语言)

    Shell命令行解释简介

    Shell 是一个命令行解释Shell 为用户提供了与设备进行命令行交互的方式,用户通过串口
    的头像 发表于 08-19 17:20 3168次阅读

    Linux命令行shell脚本编写

    Linux命令行shell脚本编写
    发表于 01-11 16:50 4次下载

    如何在Linux命令行中运行Python脚本

    Python 是一种高级编程语言,被广泛应用于数据科学、机器学习、Web 开发等领域。在 Linux 操作系统中,Python 是一个默认安装的解释,用户可以通过命令行界面(CLI)
    的头像 发表于 05-12 14:49 1653次阅读

    单片机上如何做shell命令行交互

    做个shell命令行交互?答案当然是可以的,在网上类似的文章和代码一搜一箩筐, 基本原理: 监测用户的输入,然后到一个命令查找表里过滤是否可以找到该命令,如果可以则调用对应的处理函数,
    的头像 发表于 11-01 15:16 1280次阅读

    shell命令linux命令一样吗

    Shell命令Linux命令并不完全一样。 首先,Shell是一种命令行
    的头像 发表于 11-08 10:51 2724次阅读

    linux命令shell编程有什么联系

    Linux命令Shell编程之间存在密切的联系。 首先,ShellLinux命令行下的
    的头像 发表于 11-08 10:53 881次阅读

    linux命令行shell编程实战

    Linux命令行Shell编程实战主要涉及以下内容: Linux命令行基础:学习Linux
    的头像 发表于 11-08 10:57 725次阅读

    linux虚拟机怎么调出命令行

    Linux虚拟机中调出命令行界面,可以通过以下步骤实现: 打开虚拟机,进入到Linux系统。 在桌面或应用菜单中找到终端或命令行图标,点击
    的头像 发表于 11-08 11:28 2981次阅读

    linux切换到命令行模式

    Linux中,可以通过以下步骤切换到命令行模式: 打开终端。可以在应用菜单中找到终端或命令行终端。 在终端中输入命令“exit”或“logout”,然后按回车键。 系统会提示您输入管
    的头像 发表于 11-13 16:47 1712次阅读

    linux命令行运行步骤

    运行Linux命令行涉及以下步骤: 打开终端 在Linux系统中,打开命令行界面的方式有多种,最常见的是打开终端应用程序。可以在应用程序菜单中找到终端,点击打开。 熟悉
    的头像 发表于 11-17 10:18 746次阅读