您的位置:首页 > 运维架构 > Shell

操作系统上机——实现一个简单的shell

2012-03-21 22:28 519 查看
原题见《操作系统—精髓与设计原理(第五版)》一书110页。

 

这里是实现代码。实现了基本的功能,主要通过系统调用,实验环境为Fedora 16 linux 。

//myshell.h

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_BUFFER 1024      //字符串长度最大值
#define MAX_ARGS 64          //参数最大数量
#define SWEPARATOR " \n\t"

//myshell.c

 

/**********************************************************
myshell-basic shell replacement
>my shell
从键盘输入一行字符串,分割字符串并解析为cmd命令
clr 清屏
ls <directory> 列出<directory>目录下面的文件,默认为当前目录
environ 环境变量
quit 退出
**********************************************************/

#include<myshell.h>

extern char **environ;

/**********************************************************/

int main(int argc,char** argv)
{
//system("title MyShell");
char linebuf[MAX_BUFFER];
char cmndbuf[MAX_BUFFER];
char *args[MAX_ARGS];
char **arg;
char* prompt="==>";
while(!feof(stdin))
{
system("pwd");
fputs(prompt,stdout);
fflush(stdout);
//输入参数
if(fgets(linebuf,MAX_BUFFER,stdin))
{
arg=args;
*arg++=strtok(linebuf,SWEPARATOR);//按空格,换行符,制表符等分割字符串
while((*arg++=strtok(NULL,SWEPARATOR)));
if(args[0])//第一个参数存在
{
//printf("args[0]:%s\n",args[0]);
cmndbuf[0]=0;
//printf("cmndbuf[0]:%c\n%s\n",cmndbuf[0],args[0]);
//检查是否为系统已经存在的命令
if(!strcmp(args[0],"clr"))
{
strcpy(cmndbuf,"clear");
}
else if(!strcmp(args[0],"dir"))
{
strcpy(cmndbuf,"ls ");
if(!args[1])
{
args[1]=".";//没输入参数默认为当前目录
}
strcat(cmndbuf,args[1]);
//printf("%s",cmndbuf);
}
else if(!strcmp(args[0],"help"))
{
strcpy(cmndbuf,"more ./readme");//显示当前目录下的readme
}
else if(!strcmp(args[0],"pause"))
{
//printf("Press enter to continue...\n");//提示暂停,直到按下回车键
strcpy(cmndbuf,"read -n 1 -p \"Press any key to continue...\"");
//	char temp=malloc(sizeof(char));
//	scanf("%c",&temp);
//	while(strcmp(temp,'\n'))
//	{
//		scanf("%c",&temp);
//	}

}

else if(!strcmp(args[0],"cd"))
{
if(!args[1])
{
args[1]=".";//没输入参数默认为当前目录
}
int result=chdir(args[1]);
if(result<0)
{printf("Error:directory not exist!\n");}
}
else if(!strcmp(args[0],"environ"))
{
char** envstr=environ;
while(*envstr)
{
printf("%s\n",*envstr);
envstr++;
}

}
else if(!strcmp(args[0],"quit"))
{
break;//return 0,退出循环
}
else      //其他命令
{
int i=1;
strcpy(cmndbuf,args[0]);
while(args[i])
{
strcat(cmndbuf," ");
strcat(cmndbuf,args[i++]);
}
}
//调用系统命令
if(cmndbuf[0])
{
system(cmndbuf);
}

}
}
}
return 0;

} 

其中的cd命令通过chdir函数实现。通过查资料和实验得知,在shell里面直接用cd命令实现工作目录切换不可以,因为system(command)是通过创建子进程实现系统命令调用,原则上是子进程执行cd命令,shell并未改变目录,因此必须通过其他方式比如调用chdir函数实现。

 

以下是makefile

#makefile

myshell:myshell.c myshell.h

gcc -I. myshell.c -o myshell

 

以下是readme

//readme

 

myshell - 一个简单的shell

概要
myshell

版权
myshell is Copyright (C) 2012 by Duan Cong.

介绍
myshell 是一个简单的shell程序,通过它你可以用来实现简单的命令行操作,比如列出目录下面的文件,清屏等等。

用法
在终端下输入myshell,即可打开程序。

后台运行:在终端下输入myshell时,紧接着输入一个&,即输入myshell&。

功能
当进入myshell后,你可以通过输入相应命令实现以下功能:

cd [directory] —— 把当前默认目录改变为[directory]。不输入参数默认为当前目录。
dir [directory] —— 列出目录[directory]的内容。不输入参数默认为当前目录。
clr —— 清屏。
environ —— 列出所有的环境变量。
echo [comment] —— 在屏幕上显示[comment]并换行。
help —— 显示本用户手册。
quit —— 退出myshell。

还调用其他程序和系统命令。

说明
输入输出重定向功能:
在myshell中使用命令行如programname arg1 arg2 > outputfile 时,programname的输出将输出到outputfile里而不是显示屏幕上。如果outputfile已存在则覆盖已有文件,如果不存在则创建输出文件。
在myshell中使用命令行如programname arg1 arg2 >> outputfile 时,programname的输出将追加到outputfile里而不是显示屏幕上。如果outputfile已存在则将输出添加到已有文件尾部,如果不存在则创建输出文件。

示例
当前目录为/home/dc,在终端下输入myshell,显示如下:

[dc@localhost ~]$ myshell
/home/dc
==>

说明已经进入程序。
继续输入dir,显示如下:

/home/dc
==>dir
A	    Desktop    index.php      note.xml	Public	   Untitled 1.docx
Audiobooks  Documents  index.php.bak  Pictures	Templates  Videos
blog.docx   Downloads  Music	      Podcasts	test.txt
/home/dc
==>

输入clr,显示如下:

/home/dc
==>

屏幕被清空。
输入environ,显示如下(中间省略部分环境变量,用省略号代替):

/home/dc
==>environ
XDG_VTNR=1
XDG_SESSION_ID=2
HOSTNAME=localhost.localdomain
IMSETTINGS_INTEGRATE_DESKTOP=yes
GPG_AGENT_INFO=/tmp/keyring-sFt4mm/gpg:0:1
TERM=xterm
SHELL=/bin/bash
...
XAUTHORITY=/var/run/gdm/auth-for-dc-mesabL/database
_=/home/dc/Desktop/operating_system/project/myshell
OLDPWD=/home/dc/Desktop/operating_system/project
/home/dc
==>

输入dir /,显示如下:

/home/dc
==>dir /
bin   dev  home  lost+found  mnt  proc	run   srv  tmp	var
boot  etc  lib	 media	     opt  root	sbin  sys  usr
/home/dc
==>

另外,myshell可以调用其他程序,例如输入gedit,将调用GUI的文本编辑器gedit,在终端中按下ctrl+C可以结束gedit进程。

在myshell中输入quit,退出myshell,返回终端,显示如下:

/home/dc
==>quit
[dc@localhost ~]$

以上仅为部分示例,更多详细请参考“功能”。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息