手搓shell
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ZERO '\0'
#define SIZE 512
#define SEP " "
#define NUM 32
#define Skiopath(p) do{ p += strlen(p-1);while(*p!='/')p--;}while(0)
#define SkipSpace(cmd,pos) do{while(1){if(isspace(cmd[pos]))pos++;else break;}}while(0)
#define None_Redir 0
#define In_Redir 1
#define Out_Redir 2
#define App_Redir 3
int redir_type = None_Redir;
char* filename =NULL;
char *gArgv[NUM];
char cwd[SIZE*2];
int lastcode =0;
void Die()
{
exit(1);
}
const char *Gethome()
{
const char *home =getenv("HOME");
if(home==NULL)return "/";
return home;
}
const char *GetuserName()
{
const char *name= getenv("USER");
if(name==NULL)return "None";
return name;
}
const char *GethostName()
{
const char *hostname = getenv("HOSTNAME");
if(hostname==NULL)return "None";
return hostname;
}
const char *GetCwd()
{
const char *cwd=getenv("PWD");
if(cwd==NULL)return "None";
return cwd;
}
void Makecommandline_print()
{
char line[SIZE];
const char *username = GetuserName();
const char *hostname = GethostName();
const char *cwd = GetCwd();
Skiopath(cwd);
snprintf(line,SIZE,"[%s@%s %s]> ",username,hostname,strlen(cwd)==1?"/":cwd+1);
printf("%s",line);
fflush(stdout);
}
int Getusercommand(char command[],size_t n)
{
char *s = fgets(command,n,stdin);
if(s==NULL)return 1;
command[strlen(command)-1]=ZERO;
return strlen(command);
}
void Splitcommand(char command[],size_t n)
{
gArgv[0] = strtok(command,SEP);
int index =1;
while((gArgv[index++]=strtok(NULL,SEP)));
}
void Executecommand()
{
pid_t id =fork();
if(id<0) Die();
else if(id==0)
{
if(filename != NULL)
{
if(redir_type == In_Redir)
{
int fd =open(filename,O_RDONLY);
dup2(fd,0);
}
else if(redir_type == Out_Redir)
{
int fd =open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666);
dup2(fd,1);
}
else if(redir_type == App_Redir)
{
int fd =open(filename,O_WRONLY | O_CREAT | O_APPEND,0666);
dup2(fd,1);
}
else
{}
}
execvp(gArgv[0],gArgv);
exit(errno);
}
else{
int status =0;
pid_t rid = waitpid(id,&status,0);
if(rid>0)
{
lastcode = WEXITSTATUS(status);
if(lastcode!=0)printf("%s:%s:%d\n",gArgv[0],strerror(lastcode),lastcode);
}
}
}
void Cd()
{
const char *path = gArgv[1];
if(path==NULL)path=Gethome();
chdir(path);
char temp[SIZE*2];
getcwd(temp,sizeof(temp));
snprintf(cwd,sizeof(cwd),"PWD=%s",temp);
putenv(cwd);
}
int Checkbuilding()
{
int yes =0;
const char *enter_cmd = gArgv[0];
if(strcmp(enter_cmd,"cd")==0)
{
yes =1;
Cd();
}
else if(strcmp(enter_cmd,"echo")==0&&strcmp(gArgv[1],"$?")==0)
{
yes=1;
printf("%d\n",lastcode);
lastcode=0;
}
return yes;
}
void CheckRedir(char cmd[])
{
int pos =0;
int end=strlen(cmd);
while(pos < end)
{
if(cmd[pos] == '>')
{
if(cmd[pos+1] == '>')
{
cmd[pos++] = 0;
pos++;
redir_type = App_Redir;
SkipSpace(cmd,pos);
filename = cmd +pos;
}
else{
cmd[pos++] = 0;
redir_type = Out_Redir;
SkipSpace(cmd,pos);
filename = cmd +pos;
}
}
else if(cmd[pos] == '<')
{
cmd[pos++]=0;
redir_type = In_Redir;
SkipSpace(cmd,pos);
filename = cmd+pos;
}
else
{
pos++;
}
}
}
int main()
{
int quit =0 ;
while(!quit)
{
redir_type = None_Redir;
filename =NULL;
Makecommandline_print();
char usercommand[SIZE];
int n = Getusercommand(usercommand,sizeof(usercommand));
CheckRedir(usercommand);
Splitcommand(usercommand,sizeof(usercommand));
n=Checkbuilding();
if(n)continue;
Executecommand();
}
return 0;
}