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

    文章

    10942

    浏览量

    206544
  • 命令行
    +关注

    关注

    0

    文章

    75

    浏览量

    10339
  • Shell
    +关注

    关注

    1

    文章

    356

    浏览量

    22890
  • 进程
    +关注

    关注

    0

    文章

    190

    浏览量

    13867
  • 解释器
    +关注

    关注

    0

    文章

    97

    浏览量

    6415

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

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

收藏 人收藏

    评论

    相关推荐

    在STM32实现命令行

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

    linux命令行操作和shell的区别 / 服务选购!

    在一起,形成一个相当于面向过程的程序,shell script,来实现一些较为复杂的功能。总括,shelllinux命令集的概称,是属于
    发表于 03-27 14:54

    Shell命令行记录

    Shell命令行Tips整理【持续更新】
    发表于 10-21 06:36

    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编辑器的使用手册

    Linux命令行shell脚本编程宝典PDF版电子书免费下载

    Linux系统中,命令shell脚本是非常重要的内容,它们的功能非常强大,使用它们可以完成各种操作。《Linux命令行和sheell脚本
    发表于 03-20 13:41 0次下载

    Linux命令行shell脚本编程大全第3版PDF电子书免费下载

    这是一本关于 Linux 命令行shell 脚本编程的全方位教程,主要包括四大部分 :Linux 命令行
    发表于 08-12 08:00 0次下载

    Linux命令行shell脚本编程大全第3版电子书免费下载

    这是一本关于 Linux 命令行shell 脚本编程的全方位教程,主要包括四大部分 :Linux 命令行
    发表于 05-08 08:00 0次下载

    Linux 命令行教程好书推荐

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

    Shell命令行解释器简介

    Shell 是一个命令行解释器,Shell 为用户提供了与设备进行命令行交互的方式,用户通过串口、以太网、无线等方式将
    的头像 发表于 08-19 17:20 2641次阅读

    Linux命令行shell脚本编写

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

    shell命令linux命令一样吗

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

    linux命令shell编程有什么联系

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

    linux命令行shell编程实战

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

    linux虚拟机怎么调出命令行

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

    linux命令行运行步骤

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