http://3270239.blog.51cto.com/3260239/884166
今天研究了简单的shell解释器,里面就虽然只可以解释几条简单的命令,但是看了一些资料,可以调用外部命令,这样的话简单的shell就不简单 了呵呵,我现在还在继续研究,尽量完善,争取写出属于自己的“不简单”的shell解释器。源代码过些时日再发布,就发在此空间,望高手指教,目前为止, 我自己写的shell(minish)可以获得用户名、主机名、路径,包括cd echo help jobs pwd quit等命令,还正在慢慢添加命令。经过一段时间学习,由于鄙人初学,有些命令的加入还是有些难度的,现在把源代码发布,望朋友们指正。
虽然代码短小、功能简单,但毕竟是本人花一段时间,参考一些资料写的,假如转载请注明出处,谢谢!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <grp.h>
#include <string.h>
#include <pwd.h>
#include <libgen.h>
#include <sys/types.h>
#define CMDNUM 100
struct PRO{
int p_num;
char p_name[20];
pid_t p;
int state;
} process[100];
int Analyse(char cmd[],char *arg[],char buf[]);
int func_choice(char cmd[],char *arg[]);
int Help();
int Echo(char *arg[]);
int Cd(char *arg[]);
int Pwd(char *arg[]);
int JobList();
int Record(char cmd[],pid_t p);
int Now=0;
int main()
{
int i;
char path[1024],*username,host[100],tmp[80];
struct group *data;
char *arg[100],cmd[100],buf[200];
data=getgrgid(getgid());
username=data->gr_name;
strcat(tmp,username);
for(i=0;i<100;i++){
process[i].p_num=0;
process[i].state=0;
}//初始化进程记录数组
//////存入父进程
printf("\n******Welcome to MiniShell******\n");
printf("********CopyRight@prince********\n");
printf("****首次使用请输入命令:help****\n\n");
process[0].p_num = 1;
strcpy(process[0].p_name,"minish");
process[0].p=getpid();
process[0].state = 1;
while(1){
Now = 0;
if(gethostname(host, 99) == -1) {
strcpy(host, "localhost");
}
/* if(!getcwd(path, 99)) {
strcpy(path, "unknown");
} else {
if(strcmp(path, "/")!= 0)
strcpy(path, basename(path));
} */
if( getcwd(path,1024) == NULL)
printf("获取路径失败!\n");
if(strcmp(username,"root")==0)//判断是否为超级用户
printf("%s@%s:[%s]# ",username,host,path);
else printf("%s@%s:[%s]$ ",username,host,path);
if( (fgets(buf,200,stdin)!=NULL) && (*buf != '\n') ){
buf[strlen(buf)-1] = '\0';
if(buf[strlen(buf)-2] == '&') Now=1;
if( !strcmp(buf,"quit") || !strcmp(buf,"exit") || !strcmp(buf,"bye"))
return 0;
Analyse(cmd,arg,buf);
func_choice(cmd,arg);
}
}
return 0;
}
//命令解析
int Analyse(char cmd[],char *arg[],char str[])
{
int i=0;
char *p=NULL;
while( (p = strsep(&str," ")) != NULL)
{
if(i==0)
strcpy(cmd,p);
arg[i++]=p;
}
if( !strcmp(arg[i-1],"&"))
{
arg[i-1] = '\0';
Now=1;
}
else
arg[i]=NULL;
return 0;
}
/*根据输入指令执行相应程序*/
int func_choice(char cmd[],char *arg[])
{
// int i;
pid_t pid;
//内部命令
if( !strcmp(cmd,"help"))
Help();
else if( !strcmp(cmd,"echo"))
Echo(arg);
else if( !strcmp(cmd,"environ"))
Environ();
else if( !strcmp(cmd,"cd"))
Cd(arg);
else if( !strcmp(cmd,"jobs"))
JobList();
else if(!strcmp(cmd,"pwd"))
Pwd(arg);
else//外部命令
{
pid = fork();
if( pid > 0)
{
Record(cmd,pid);
}
if( pid < 0 )
{
printf("fork error\n");
}
if(pid == 0)
{
if( (execvp(cmd,arg)) < 0 )
printf(" 文件或目录不存在!\n");
else
{
Record(cmd,pid);
}
}
}
if(Now)
waitpid(pid,0,WNOHANG);
else
waitpid(pid,0,0);
return 0;
}
//cd:修改当前的工作目录到另一个目录
int Cd(char *arg[])
{
if( chdir(arg[1]))
printf("目录不存在!");
return 0;
}
//pwd:显示当前的所在的工作目录
int Pwd(char *arg[])
{
char path[1024];
if( getcwd(path,1024) == NULL)
printf("获取路径失败!\n");
printf("**%s**\n",path);
return 0;
}
//help
int Help()
{
printf("\n\n\n\t*****************************************************\n");
printf("\t Welcome to The MiniShell \n");
printf("\t-----------------------------------------------------\n");
printf("\t欢迎使用简易版Shell程序,本程序具备以下功能: \n");
printf("\t cd: 修改当前的工作目录到另一个目录 \n");
printf("\t pwd: 显示当前的所在的工作目录 \n");
printf("\t echo: 显示echo后的内容且换行 \n");
printf("\t help: 简要介绍Shell的使用方法以及功能 \n");
printf("\t jobs: 输出当前Shell下都一系列子进程 \n");
printf("\t quit: 退出Shell \n");
printf("\t------------------------------------------------------\n");
printf("\t 制作时间:2012年5月20日\n");
printf("\t 版权所有: prince \n");
printf("\t*****************************************************\n\n\n");
return 0;
}
//Echo:显示echo后的内容且换行
int Echo(char *arg[])
{
int i=1;
while(arg[i] != NULL)
{
printf("%s ",arg[i++]);
}
printf("\n");
return 0;
}
//env
int Environ()
{
if( (execl("/bin/env","env",(char *)0)) < 0 )//功能ENV实现
printf("execl error\n");
return 0;
}
//Jobs:输出当前Shell下都一系列子进程
int JobList()
{
int i;
printf("PID\t进程\t状态\n");
for(i=0;i<100;i++)
{
if(process[i].state == 1){
printf("%d\t%s\t",process[i].p,process[i].p_name);
printf("RUNNING\n");
}
}
return 0;
}
//记录
int Record(char cmd[],pid_t p)
{
int i;
for(i=0;i<100;i++)
{
if(process[i].state != 1)
{
strcpy(process[i].p_name,cmd);
process[i].state = 1;
if(p>0) process[i].p = p;
break;
}
}
return 0;
}