![]() |
#2
oped022022-11-03 09:41
|

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>
pid_t pid;
int bg = 0;//是否后台运行
char commands[256][256];//分割后的命令
int inNum, outNum;//是否有重定向输出输入
int pipe_command(int, int);
//父进程处理信号函数
void signalCat() {
if (pid != 0) {
kill(pid, SIGINT);
int status;
waitpid(pid, &status, 0);
}
}
//分割命令并返回条数
int split(char *command) {
int num = 0;
int i, j;
int len = strlen(command);
for (i = 0, j = 0; i < len; i++) {
if (command[i] != ' ') {
commands[num][j++] = command[i];
} else {
if (j != 0) {
commands[num][j] = '\0';
num++;
j = 0;
}
}
}
if (j != 0) {
commands[num][j] = '\0';
num++;
}
return num;
}
//执行函数
int redo_command(int l, int r) {
char *inFile = NULL, *outFile = NULL;
int in_h = r, out_h = r, flag = 0;
//寻找重定向
for (int i = l; i < r; i++) {
if (strcmp(commands[i], "<") == 0) {
inNum++;
if (i + 1 < r) {
inFile = commands[i + 1];
} else {
perror("in have no parameter\n");
return -1; //重定向符号后缺少文件名
}
in_h = i;
}
if (strcmp(commands[i], ">") == 0 || strcmp(commands[i], ">>") == 0) {
outNum++;
if (i + 1 < r) {
outFile = commands[i + 1];
} else {
perror("out have no parameter\n");
return -1; //重定向符号后缺少文件名
}
out_h = i;
if (strcmp(commands[i], ">>")==0) flag = 1;
}
}
//如果多个重定向,错误
if (inNum > 1 || outNum > 1) {
perror("have too much in and out\n");
return -1;
}
//分段递归执行
int max_h = in_h;
if (in_h < out_h) max_h = out_h;
int result = 0;
pid = fork();
int min_h = in_h;
if (in_h > out_h) min_h = out_h;
if (inNum == 1)
freopen(inFile, "r", stdin);
if (outNum == 1) {
if (flag == 0)
freopen(outFile, "w", stdout);
else
freopen(outFile, "a", stdout);
}
if (pid < 0) {
perror("creat process fail\n");
result = -1;
} else if (pid == 0) {
char *comm[256];
int tag = 0;
for (int i = l; i < min_h; i++)
comm[tag++] = commands[i];
comm[tag] = NULL;
execvp(comm[0], comm);
perror("input error!\n");
exit(EXIT_FAILURE);
} else {
if (abs(in_h - out_h) > 2) {
pipe_command(min_h + 2, max_h);
}
if (max_h + 1 < r) pipe_command(max_h + 2, r);
int status;
if (bg == 0) {
waitpid(pid, &status, 0);
} else {
printf("BACKGROUND RUNNING\n");
}
}
return result;
}
//是否有管道,有管道就相当于父子进程间的通信
int pipe_command(int l, int r) {
if (l >= r) return 0;
int pipe_h = -1; //判断是否有管道命令
for (int i = l; i < r; i++) {
if (strcmp(commands[i], "|") == 0) {
pipe_h = i;
break;
}
}
if (pipe_h == -1) { //无管道命令
return redo_command(l, r);
} else if (pipe_h + 1 == r) { //管道命令'|'后没有指令,也就是没有参数
printf("| have no parameter\n");
return -1;
}
//开始执行命令
int pipe_id[2];
if (pipe(pipe_id) < 0) {
perror("create pipe error\n");
return -1;
}
int result = 0;
pid = fork();
if (pid == -1) {
result = -1;
} else if (pid == 0) {//子进程执行单个命令
close(pipe_id[0]);
dup2(pipe_id[1], STDOUT_FILENO); //将标准输出重定向到pipe_id[1]
result = redo_command(l, pipe_h);
exit(result);
} else { // 父进程递归执行后续命令
int status;
waitpid(pid, &status, 0);
if (pipe_h + 1 < r) {
close(pipe_id[1]);
dup2(pipe_id[0], STDIN_FILENO);
result = pipe_command(pipe_h + 1, r);
}
}
return result;
}
int main() {
signal(SIGINT, signalCat);
read_history(NULL);
while (1) {
inNum = 0;
outNum = 0;
char *argv;
argv = readline("Myshell$ ");
add_history(argv);
int len = strlen(argv);
if (strcmp(argv, "exit") == 0) {
printf("thanks for your use!\n");
exit(EXIT_SUCCESS);
}
if (argv[len - 1] == '&') {//是否后台
bg = 1;
argv[len - 1] = '\0';
} else bg = 0;
int commandNum = split(argv);
// for (int i = 0; i < commandNum; i++) {
// printf("%s\n", commands[i]);
// }
// 获取标准输入、输出的文件标识符
int inPipe = dup(STDIN_FILENO);
int outPipe = dup(STDOUT_FILENO);
pipe_command(0, commandNum);
//还原标准输入、输出重定向
dup2(inPipe, STDIN_FILENO);
dup2(outPipe, STDOUT_FILENO);
free(argv);
}
return 0;
}