操作系统头歌实验五 Shell综合练习

 题目详情:综合利用进程控制的相关知识,结合对shell功能的和进程间通信手段的认知,编写简易shell程序,加深操作系统的进程控制和shell接口的认识。

编程要求

1.尝试自行设计一个C语言小程序,完成最基本的shell角色:给出命令行提示符、能够逐次接受命令;对于命令分成三种,内部命令(实现help命令、cd命令、exit命令)、外部命令(常见的ls、cp等,以及其他磁盘上的可执行程序HelloWrold等,可以用同一方法处理)以及无效命令(不是上述两种命令)。

2.将上述shell进行扩展,使得你编写的shell程序具有支持管道的功能,也就是说你的shell中输入“dir | more”能够执行dir命令并将其输出通过管道将其输入传送给more作为标准输入。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>

#include <dirent.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <sys/wait.h>

//define定义各个变量的基本数字
#define maxn 10000
#define maxargnumber 60
#define minn 1
#define maxvarnumber 60
#define maxstrnumber 20
#define maxstring 90
#define maxstrlen 255
#define minstring 10
#define TRUE 1
#define ERROR 0
#define maxpathlen 256
#define maxbuflen 4096
#define maxcharshuzu 100
#define maxvarlen 600
#define ferror 2
#define eerror 3
struct str {
	struct str* next;
	int start, end, temp;
	char lpoint, rpoint;
	char tofile[maxpathlen], comefile[maxpathlen];
	char* args[maxargnumber];
	char failexec;
};
//定义备用结构体
struct com {
	struct com* head;
	int one, second;
};
//标记状态码
enum {
	errorexit,
	errorsystem,
	renormal,
};
char username[maxcharshuzu];
char hostname[maxcharshuzu];
char curpath[maxcharshuzu];
struct str stri[maxstrnumber];
int strnumber, varnumber;
char conduct[maxstrlen];
char commands[maxcharshuzu][maxcharshuzu];
char var[maxvarnumber][maxpathlen];

void hanshu(int a) {
	for (int i = 0; i < a; i++) {
		struct com co;
		co.one = i + 1;
		co.second = i - 1;
	}
}
int getexit() {
		pid_t pid = getpid();
		if (kill(pid, SIGTERM) == -1) {
			return errorexit;
		}
		else {
			return renormal;
		}
}
	

void init(struct str* a) {
	a->failexec = 0; a->temp = 0;
	a->lpoint = 0; a->rpoint = 0;
	a->next = NULL;
	a->start = -1; a->end = -1;
	for (int i = 0; i < maxargnumber; i++) {
		a->args[i] = NULL;
	}
}

void wrong(int a) {
	switch (a) {
	case ferror:
		printf("进程分割错误\n");
		break;
	case eerror:
		printf("启动其他进程错误\n");
		break;
	default:
		printf("错误,然后退出\n");
	}
	exit(1);
}

int haveinput() {
	int x, y; x = 0;
	char z; z = 1;
	while (z) {
		y = maxstrlen - x;
		if (y <= 0) {
			printf("进程启动时间超限\n");
			return -1;
		} 
		z = 0; fgets(conduct + x, y, stdin);
		while (1) {
			if (conduct[x] == '\\' && conduct[x + 1] == '\n') {
				z = 1;
				conduct[x] = '\0';
				x++;
				break;
			}
			else if (conduct[x] == '\n') {
				break;
			}
			x += 1;
		}
	}
	return x;
}

int strpoint(int a) {
	char x = 0; struct str* first;
	for (int i = 0; i <= a; i++) {
		switch (conduct[i]) {
		case '&': {
			if (conduct[i + 1] == ';' || conduct[i + 1] == '\n') {
				conduct[i] = ' '; first->failexec = 1;
			}
		}
		case '\t':
			conduct[i] = ' ';
			break;
		case ';': {
			x = 0;
			conduct[i] = '\0';
			stri[strnumber].end = i;
			strnumber += 1;
			break;
		}
		case '\n': {
			conduct[i] = '\0';
			stri[strnumber].end = i;
			strnumber += 1;
			return 0;
		}
		case ' ':
			break;
		default:
			if (!x) {
				x = 1; first = stri + strnumber;
				stri[strnumber].start = i;
			}
		}
	}
}

int item(char* a, char* b, int c) {
	int temp = 0;
	char cha;
	while (b[++c] == ' ');
	if (b[c] == '\n') {
		return -1;
	}
	while (cha = a[temp] = b[c]) {
		if (cha == ' ' || cha == '|' || cha == '<' || cha == '>' || cha == '\n') {
			break;
		}
		temp += 1; c += 1;
	}
	a[temp] = '\0';
	int com = c - 1;
	return com;
}
//
int spcommand(char command[maxcharshuzu]) {
	int num = 0,x;
	int len = strlen(command);
	for (int i = 0, x = 0; i < len; ++i) {
		if (command[i] != ' ') {
			commands[num][x++] = command[i];
		}
		else {
			if (x != 0) {
				commands[num][x] = '\0';
				++num;
				x = 0;
			}
		}
	}
	if (x != 0) {
		commands[num][x] = '\0';
		++num;
	}

	return num;
}

int checkvar(struct str* a, int b) {
	char* cha = a->args[b];
	int temp1 = 0, temp2 = 0;
	while (cha[temp1]) {
		if ((cha[temp1 - 1] != '\\') && (cha[temp1] == '$')) {
			if (cha[temp1 + 1] == '{') {
				temp1 += 2;
			}
			else temp1 += 1;
			char* cha2 = &var[varnumber][temp2];
			int x = 0;
			while (cha2[x] = cha[temp1]) {
				if (cha2[x] == '}') {
					++temp1;
					break;
				}
				if (cha2[x] == ' ' || cha2[x] == '\n' || cha2[x] == '\0')break;
				x += 1; temp1 += 1;
			}
			cha2[x] = '\0';
			cha2 = getenv(cha2);
			for (int i = 0; var[varnumber][temp2++] = cha2[i++];);
			temp2 -= 1;
		}
		else {
			var[varnumber][temp2++] = cha[temp1++];
		}
	}
	var[varnumber][temp2] = '\0';
	a->args[b] = var[varnumber++];
	return 0;
}
void makeusername() { 
	struct passwd* a = getpwuid(getuid());
	strcpy(username, a->pw_name);
}

void makehostname() { 
	gethostname(hostname, maxpathlen);
}

int getCurWorkDir() { 
	char* result = getcwd(curpath, maxpathlen);
	if (result == NULL)
		return errorsystem;
	else {
		return renormal;
	}
}

int mobel() {
	char temp1 = 0, temp2 = 0, temp3 = 0, var = 0, c;
	int one, second;
	struct str* a;
	for (int p = 0; p < strnumber; p++) {
		if (temp1 || temp2 || temp3) {
			return -1;
		}
		a = &stri[p];
		one = a->start, second = a->end;
		init(a);
		for (int i = one; i < second; ++i) {
			c = conduct[i];
			if ((c == '\"') && (conduct[i - 1] != '\\' && (!temp2))) {
				if (temp3) {
					conduct[i] = temp3 = temp1 = 0;
					if (var) {
						var = 0;
						checkvar(a, a->temp - 1);
					}
				}
				else {
					temp3 = 1;
					a->args[a->temp++] = conduct + i + 1;
				}
				continue;
			}
			else if (temp3) {
				if ((c == '$') && (conduct[i - 1] != '\\') && (!var)) {
					var = 1;
				}
				continue;
			}

			if ((c == '\'') && (conduct[i - 1] != '\\')) {
				if (temp2) {
					conduct[i] = temp2 = temp1 = 0;
				}
				else {
					temp1 = 1;
					a->args[a->temp++] = conduct + i + 1;
				}
				continue;
			}
			else if (temp2) {
				continue;
			}
			if (c == '<' || c == '>' || c == '|') {
				if (temp1) {
					temp1 = 0;
				}
				conduct[i] = '\0';
			}
			if (c == '<') {
				if (conduct[i + 1] == '<') {
					a->lpoint += 2;
					conduct[i + 1] = ' ';
				}
				else {
					a->lpoint += 1;
				}
				int tmp = item(a->comefile, conduct, i);
				if (tmp > 0)i = tmp;
			}
			else if (c == '>') {
				if (conduct[i + 1] == '>') {
					a->rpoint += 2;
					conduct[i + 1] = ' ';
				}
				else {
					a->rpoint += 1;
				}
				int tmp = item(a->tofile, conduct, i);
				if (tmp > 0)i = tmp;
			}
			else if (c == '|') {
				a->end = i;
				a->next = (struct str*)malloc(sizeof(struct str));
				a = a->next;
				init(a);
			}
			else if (c == ' ' || c == '\0') {
				if (temp1) {
					temp1 = 0;
					conduct[i] = '\0';
				}
			}
			else {
				if (a->start == -1) {
					a->start = i;
				}
				if (!temp1) {
					temp1 = 1;
					if ((c == '$') && (conduct[i - 1] != '\\') && (!var)) {
						var = 1;
					}
					a->args[a->temp++] = conduct + i;
				}
			}
			if (var) {
				var = 0;
				checkvar(a, a->temp - 1);
			}
		}
		a->end = second;
	}
}

int ein(struct str* a) {
	if (!a->args[0])
		return 0;
	if (strcmp(a->args[0], "cd") == 0) {
		struct stat st;
		if (a->args[1]) {
			stat(a->args[1], &st);
			if (S_ISDIR(st.st_mode))
				chdir(a->args[1]);
			else {
				printf("cd '%s':cd到路径是出错\n", a->args[1]);
				return -1;
			}
		}
		return 0;
	}
	if (strcmp(a->args[0], "pwd") == 0) {
		printf("%s\n", getcwd(a->args[1], maxpathlen));
		return 0;
	}
	if (strcmp(a->args[0], "unset") == 0) {
		for (int i = 1; i < a->temp; ++i) {
			unsetenv(a->args[i]);
		}
		return 0;
	}
	if (strcmp(a->args[0], "export") == 0) {
		for (int i = 1; i < a->temp; ++i) { 
			char* val, * p;
			for (p = a->args[i]; *p != '='; ++p);
			*p = '\0';
			val = p + 1;
			setenv(a->args[i], val, 1);
		}
		return 0;
	}
	if (strcmp(a->args[0], "exit") == 0) {
        exit(0);
	}
	return 1;
}
void IO(struct str* a, int b, int c) {
	if (a->rpoint > 0) {
		int flag;
		if (a->rpoint == 1) {
			flag = O_WRONLY | O_TRUNC | O_CREAT;
		}
		else {
			flag = O_WRONLY | O_APPEND | O_CREAT;
		}
		int wport = open(a->tofile, flag);
		dup2(wport, STDOUT_FILENO);
		close(wport);
	}
	if (a->lpoint > 0) {
		int rport = open(a->comefile, O_RDONLY);
		dup2(rport, STDIN_FILENO);
		close(rport);
	}
	if (b != STDIN_FILENO) {
		dup2(b, STDIN_FILENO);
		close(b);
	}
	if (c != STDOUT_FILENO) {
		dup2(c, STDOUT_FILENO);
		close(c);
	}
}

int eout(struct str*a) {
	if (!a->next) {
		IO(a, STDIN_FILENO, STDOUT_FILENO);
		execvp(a->args[0], a->args);
	}
	int fd[2];
	pipe(fd);
	pid_t pid = fork();
	if (pid < 0) {
		wrong(ferror);
	}
	else if (pid == 0) {
		close(fd[0]);
		IO(a, STDIN_FILENO, fd[1]);
		execvp(a->args[0], a->args);
		wrong(eerror);
	}
	else {
		wait(NULL);
		a = a->next;  
		close(fd[1]);
		IO(a, fd[0], STDOUT_FILENO);
		eout(a);
	}
}

void dbug(struct str*a);

int main(){
	int k,l=1;
	struct com s;
	for (int i = 0; i < minstring; i++) {
		s.head->one = i;
		s.one = i + 1;
		s.second = i - 1;
	}
	//获得当前用户、主机名字
	makeusername();
	makehostname();
	while (l) {
		strnumber = 0;
		varnumber = 0;
		fflush(stdin);
		int n = haveinput();
		if (n <= 0) {
			continue;
		}
		strpoint(n);
		if (mobel() < 0) {
			continue;
		}
		int status;
		for (int i = 0; i < strnumber; ++i) {
			struct str* a = stri+1,*temp;
			status= ein(a);
			if (status == 1) {
				pid_t pid = fork();
				if (pid == 0) {
                    eout(a);
				}
				else if (pid < 0) {
					wrong(ferror);
				}
				if (!a->temp) {
					wait(NULL);
				}
				a = a->next;
				while (a) {
					temp = a->next;
					free(a);
					a = temp;
				}
			}
		}

	}
	return 0;
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stearm210

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值