1、编写一个C程序 增加功能以使用户可以使用“&”操作符作为命令的结束符。一个以“&”结尾的命令应该与shell并发执行。 增加功能以使用户可以使用“<”和“>”作为文件名前缀来重定向stdin和stdout描述符。同样,允许用户使用管道操作符“|”来同时执行两个进程,并把第一个进程的stdout重定向为第二个进程的stdin。
时间: 2023-09-17 19:08:41 浏览: 96
以下是一个简单的C程序,可以实现您的要求:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#define MAX_ARGS 10 // 最大参数数目
#define MAX_ARG_LEN 50 // 最大参数长度
int execute(char **args, int background, int input, int output, int pipe_to);
char **parse_input(char *input) {
char **args = malloc(MAX_ARGS * sizeof(char *));
char *arg = strtok(input, " \t\n"); // 使用空格、制表符和换行符作为分隔符
int i = 0;
while (arg != NULL) {
args[i++] = arg;
arg = strtok(NULL, " \t\n");
}
args[i] = NULL; // 参数列表以NULL结尾
return args;
}
int main() {
char input[100];
int should_run = 1;
while (should_run) {
printf("shell> ");
fflush(stdout);
fgets(input, sizeof(input), stdin); // 从标准输入读取用户输入
input[strlen(input) - 1] = '\0'; // 去除字符串末尾的换行符
// 检查是否以“&”结尾,表示后台执行
int background = 0;
if (input[strlen(input) - 1] == '&') {
background = 1;
input[strlen(input) - 1] = '\0';
}
// 检查是否有输入重定向
int input_fd = 0;
char *input_file = strstr(input, "<");
if (input_file != NULL) {
*input_file = '\0'; // 将输入文件名与命令分开
input_file += 2; // 跳过“< ”前缀
input_fd = open(input_file, O_RDONLY);
if (input_fd == -1) {
perror("open");
continue;
}
}
// 检查是否有输出重定向
int output_fd = 0;
char *output_file = strstr(input, ">");
if (output_file != NULL) {
*output_file = '\0'; // 将输出文件名与命令分开
output_file += 2; // 跳过“> ”前缀
output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (output_fd == -1) {
perror("open");
continue;
}
}
// 检查是否有管道
int pipe_fd[2] = {0, 0};
char *pipe_to = strstr(input, "|");
if (pipe_to != NULL) {
*pipe_to = '\0'; // 将第一个命令与管道符分开
pipe_to += 2; // 跳过“| ”前缀
if (pipe(pipe_fd) == -1) {
perror("pipe");
continue;
}
}
// 解析用户输入,生成参数列表
char **args = parse_input(input);
// 执行命令
int status = execute(args, background, input_fd, output_fd, pipe_fd[1]);
if (status == -1) {
printf("Error executing command.\n");
}
// 关闭文件描述符
if (input_fd != 0) {
close(input_fd);
}
if (output_fd != 0) {
close(output_fd);
}
if (pipe_fd[0] != 0) {
close(pipe_fd[0]);
}
if (pipe_fd[1] != 0) {
close(pipe_fd[1]);
}
// 释放内存
int i = 0;
while (args[i] != NULL) {
free(args[i]);
i++;
}
free(args);
}
return 0;
}
int execute(char **args, int background, int input, int output, int pipe_to) {
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return -1;
} else if (pid == 0) {
// 子进程
// 处理输入重定向
if (input != 0) {
if (dup2(input, STDIN_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
// 处理输出重定向
if (output != 0) {
if (dup2(output, STDOUT_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
// 处理管道
if (pipe_to != 0) {
if (dup2(pipe_to, STDOUT_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
close(pipe_to);
}
// 执行命令
if (execvp(args[0], args) == -1) {
perror("execvp");
exit(EXIT_FAILURE);
}
} else {
// 父进程
// 如果命令以“&”结尾,不等待子进程执行完毕
if (!background) {
int status;
waitpid(pid, &status, 0);
return status;
}
}
return 0;
}
```
该程序使用了标准C库提供的函数和系统调用来实现输入重定向、输出重定向、管道和后台执行等功能。当用户输入一条命令时,程序会解析命令,生成参数列表,并在子进程中执行该命令。如果命令以“&”结尾,子进程将在后台执行,父进程不会等待其完成。如果命令包含输入重定向、输出重定向或管道,程序会相应地修改文件描述符。
阅读全文