编写一个C程序作为Linux内核的shell命令行解释程序。Shell程序应该使用与Bource shell相同的方式运行程序。 增加功能以使用户可以使用“&”操作符作为命令的结束符。一个以“&”结尾的命令应该与shell并发执行。 增加功能以使用户可以使用“<”和“>”作为文件名前缀来重定向stdin和stdout描述符。同样,允许用户使用管道操作符“|”来同时执行两个进程,并把第一个进程的stdout重定向为第二个进程的stdin
时间: 2023-12-06 09:44:39 浏览: 97
由于编写一个完整的Linux内核的shell命令行解释程序需要较长的时间和精力,这里我提供一个简单的C程序,可以实现用户输入命令并执行,支持“&”操作符作为命令的结束符、重定向stdin和stdout描述符,以及管道操作符“|”来同时执行两个进程并重定向。
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#define MAX_ARGS 10
#define MAX_LINE 80
int main() {
char line[MAX_LINE]; // 存储用户输入的命令行
char *args[MAX_ARGS]; // 存储解析后的命令行参数
int should_run = 1; // 控制程序是否继续运行
int bg_flag = 0; // 判断是否使用“&”操作符作为命令的结束符
int in_flag = 0; // 判断是否使用“<”作为文件名前缀来重定向stdin描述符
int out_flag = 0; // 判断是否使用“>”作为文件名前缀来重定向stdout描述符
int pipe_flag = 0; // 判断是否使用“|”来同时执行两个进程并重定向
while (should_run) {
printf("osh> ");
fflush(stdout);
// 读取用户输入的命令行
fgets(line, MAX_LINE, stdin);
// 将命令行按空格分割成多个参数
char *token;
int i = 0;
token = strtok(line, " \n");
while (token != NULL) {
args[i] = token;
i++;
token = strtok(NULL, " \n");
}
args[i] = NULL;
// 判断是否使用“&”操作符作为命令的结束符
if (i > 0 && strcmp(args[i-1], "&") == 0) {
bg_flag = 1;
args[i-1] = NULL;
}
// 判断是否使用“<”作为文件名前缀来重定向stdin描述符
for (int j = 0; j < i; j++) {
if (strcmp(args[j], "<") == 0) {
in_flag = 1;
args[j] = NULL;
freopen(args[j+1], "r", stdin);
break;
}
}
// 判断是否使用“>”作为文件名前缀来重定向stdout描述符
for (int j = 0; j < i; j++) {
if (strcmp(args[j], ">") == 0) {
out_flag = 1;
args[j] = NULL;
freopen(args[j+1], "w", stdout);
break;
}
}
// 判断是否使用“|”来同时执行两个进程并重定向
for (int j = 0; j < i; j++) {
if (strcmp(args[j], "|") == 0) {
pipe_flag = 1;
// 将第一个进程的stdout重定向到管道写端
int fd[2];
pipe(fd);
pid_t pid = fork();
if (pid == 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execvp(args[0], args);
}
// 将第二个进程的stdin重定向到管道读端
char *args2[MAX_ARGS];
int k = 0;
args2[k] = strtok(args[j+1], " \n");
while (args2[k] != NULL) {
k++;
args2[k] = strtok(NULL, " \n");
}
args2[k] = NULL;
pid_t pid2 = fork();
if (pid2 == 0) {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
execvp(args2[0], args2);
}
// 等待两个进程执行完毕
close(fd[0]);
close(fd[1]);
waitpid(pid, NULL, 0);
waitpid(pid2, NULL, 0);
break;
}
}
// 如果没有使用“|”来同时执行两个进程并重定向,则直接执行命令
if (!pipe_flag) {
pid_t pid = fork();
if (pid == 0) {
execvp(args[0], args);
}
if (!bg_flag) {
waitpid(pid, NULL, 0);
}
}
// 重置标志位
bg_flag = 0;
in_flag = 0;
out_flag = 0;
pipe_flag = 0;
}
return 0;
}
```
在shell中,可以使用以下命令进行编译和运行:
```bash
$ gcc shell.c -o shell
$ ./shell
```
阅读全文