注意: 本文章只是为了理解shell内部的工作原理, 所以并没有完成shell的所有工作, 只是完成了shell里的一小部分工作
c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#define LEFT "["
#define RIGHT "]"
#define END "#"
#define SPLIT " "
#define LINE_SIZE 1024
#define ARGV_SIZE 32
#define EXIT_CODE 66
#define PWD_SIZE 100
int lastexit = 0;
int quit = 0;
char pwd[PWD_SIZE];
const char* getusername() {
return getenv("USER");
}
const char* mygethostname() {
return getenv("HOSTNAME");
}
void getpwd() {
getcwd(pwd, PWD_SIZE);
}
void display() {
getpwd();
printf(LEFT"%s@%s %s"RIGHT""END" ", getusername(), mygethostname(), pwd);
}
void getinput(char* cline, int size) {
char* s = fgets(cline, size, stdin);
assert(s != NULL);
cline[strlen(cline) - 1] = '\0';
//printf("%s\n", cline);
}
int split(char* cline, char* argv[]) {
int i = 0;
//printf("%s", cline);
argv[i ++] = strtok(cline, SPLIT);
while (argv[i ++] = strtok(NULL, SPLIT));
return i - 1;
}
void normalExe(char* argv[]) {
extern char** environ;
pid_t id = fork();
if (id < 0) {
perror("fork");
//continue;
} else if (id == 0) {
// child
execvpe(argv[0], argv, environ);
exit(EXIT_CODE);
}
// father
int status = 0;
pid_t ret = waitpid(id, &status, 0);
// if (ret > 0) printf("wait success pid: %d\n", ret);
if (ret > 0) lastexit = WEXITSTATUS(status);
}
int neijian(char* argv[], int argc) {
if (argc == 2 && strcmp(argv[0], "cd") == 0) {
chdir(argv[1]);
getpwd();
return 1;
}
return 0;
}
int main() {
//int quit = 0;
char cline[LINE_SIZE];
char* argv[ARGV_SIZE] = { NULL };
extern char** environ;
while (!quit) {
display();
getinput(cline, LINE_SIZE);
int tt = split(cline, argv);
if (tt == 0) continue;
//printf("%d\n", tt);
/*
int i = 0;
for (i = 0; argv[i]; ++ i)
printf("%s ", argv[i]);
printf("\n");
*/
// 内建命令执行
//内建命令本质上就是shell内部的一个函数
int n = neijian(argv, tt);
//printf("%d\n", n);
//普通命令执行
if (!n) normalExe(argv);
}
return 0;
}