我们之前已经写过相关的代码的问题了,今天我们就对随后的代码进行修改,相关的概念性的问题,在这里我就不再进行多余的赘述了。
我们知道对于Linux来说,shell就是一个命令行解释器,当我们输入相关的命令,会去执行相关的操作。
比如当我们在输入ls -a -l命令,shell就会打印出当前目录的内容,这是如何实现的呢,shell自己就是一个进程,当我们输入类似于ls的命令,它会通过fork,exec去创建一个新的子进程去执行相关操作,因此我们可以利用这个来实现一个简单的shell,当然这个shell足够的简单,并不像Linux内置的shell功能那么强大,支持各种操作,报错等等。
我们先来再聊聊如何去实现一个shell?
1、首先是提示符,rong@host以及当前路径,我们可以使用调用系统api直接打印,这里为了方便,我直接用printf函数打印。
2、解析命令,对于ls -a -l这种操作,我们只需要存入到指针数组中,char* shell_argv[32],ls存到shell_argv[0]当中,-a存到shell_argv[1],-l存到shell_argv[2]……………最后设置为一个NULL
3、利用exev进行调用新的程序。
代码如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>//isspace函数的头文件
#include <fcntl.h>
int main(){
for(;;)
{
printf("myshell@host:");
fflush(stdout);//
//解析输入到shell上的字符串 ls -a -l
char buffer[1024];
int read_size=read(1,buffer,sizeof(buffer));
if(read_size>0){
buffer[read_size-1]=0;
}
char *shell_argv[32]={NULL};
int shell_index=0;
char *start=buffer;
while(*start!='\0'){
while(*start!='\0'&& isspace(*start)){
*start='\0';
start++;
}
shell_argv[shell_index++]=start;
while(*start!='\0' && !isspace(*start)){//
start++;
}
}
//创建子进程的exec
pid_t pid=vfork();
if(pid<0){
printf("vfork failure\n");
exit(1);
}
else if(pid==0){
//考虑重定向
//从字符串数组中找重定向标志
int i=0;
int flag=0;
for(;shell_argv[i]!=NULL;++i){
if(strcmp(">",shell_argv[i])==0){
flag=1;
break;
}
}
int copyfd;
shell_argv[i]=NULL;
if(flag)
{
if(shell_argv[i+1]==NULL){
printf("command error\n");
exit(1);
}
close(1);
int fd=open(shell_argv[i+1],O_WRONLY | O_CREAT,0777);
copyfd=dup2(1,fd);//把标准输出重新定向到一个文件中
}
execvp(shell_argv[0],shell_argv);
if(flag){
close(1);
dup2(copyfd,1);
}
exit(1);
}
else //father process
{
int status=0;
int ret=waitpid(pid,&status,0);
if(ret==pid){
if(WIFEXITED(status)){
}
else if(WIFSIGNALED(status)){
printf("signal is %d\n",WTERMSIG(status));
}
}
}
}
return 0;
}
代码执行的结果:
但是这个shell暂时也只能实现这些小的命令,对于管道暂时换是不能够进行实现的。