myshell.c
cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SIZE 512
#define ZERO '\0'
#define SPACE " "
#define NUM 32
#define SkipPath(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)
// "ls -a -l -n > myfile.txt"
#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 cwd[SIZE*2];
char *gArgv[NUM];
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 "NULL";
return cwd;
}
void MakeCommandLineAndPrint()
{
char line[SIZE];
const char *username = GetUserName();
const char *hostname = GetHostName();
const char *cwd = GetCwd();
SkipPath(cwd);
snprintf( line, sizeof(line), "[%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 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;
pos++;
redir_type = Out_Redir;
SkipSpace(cmd,pos);
filename = cmd + pos;
}
}
else if(cmd[pos] == '<')
{
cmd[pos++] = 0;
pos++;
redir_type = In_Redir;
SkipSpace(cmd,pos);
filename = cmd + pos;
}
else{
pos++;
}
}
}
void SplitCommand(char* command, size_t n)
{
(void)n;
gArgv[0] = strtok(command,SPACE);
int index = 1;
while((gArgv[index++]=strtok(NULL,SPACE)));
}
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 CheckBuildin()
{
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 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);
}
}
}
int main()
{
while(1)
{
//0.先重置
redir_type = None_Redir;
filename = NULL;
//1.自制命令行
MakeCommandLineAndPrint();
//2.获取用户指令字符串
char usercommand[SIZE];
int n = GetUserCommand(usercommand, sizeof(usercommand));
if(n < 0) return 1;
//2.5检查是否需要对指令进行重定向
CheckRedir(usercommand);
// 2.2 debug
// printf("cmd: %s\n", usercommand);
// printf("redir: %d\n", redir_type);
// printf("filename: %s\n", filename);
if(n <= 0) return 1;
//3.对指令字符串进行分割
SplitCommand(usercommand,sizeof(usercommand));
//4.检查字符串是否是内建命令
n = CheckBuildin();
if(n) continue;
//5.执行命令
ExecuteCommand();
}
return 0;
}
用用看: