设计思路
- 数据结构设计:
typedef struct {
char **args;
int argc;
} Command;
- 对于管道操作,使用一个数组来存储多个
Command
结构体。
typedef struct {
Command *commands;
int num_commands;
} Pipeline;
- 命令解析:
- 使用
strtok
函数或更复杂的词法分析方法将用户输入的字符串按空格等分隔符拆分成命令和参数。
- 对于管道操作,按
|
符号拆分字符串,将每个部分分别解析为单个命令。
- 命令执行:
- 使用
fork
和execvp
函数来执行每个命令。
- 对于管道操作,利用
pipe
函数创建管道,在不同进程间传递数据。
- 错误处理:
- 在
fork
、execvp
、pipe
等函数调用后检查返回值,处理相应的错误,如内存分配失败、命令不存在等。
- 内存管理:
- 为
args
分配内存时,要确保在使用完毕后释放。同样,为commands
分配内存后,也要正确释放。
核心代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
typedef struct {
char **args;
int argc;
} Command;
typedef struct {
Command *commands;
int num_commands;
} Pipeline;
// 解析单个命令
Command parse_command(char *input) {
Command cmd;
char *token;
char *saveptr;
int i = 0;
cmd.args = (char **)malloc(10 * sizeof(char *));
if (!cmd.args) {
perror("malloc");
exit(EXIT_FAILURE);
}
token = strtok_r(input, " ", &saveptr);
while (token != NULL && i < 9) {
cmd.args[i++] = token;
token = strtok_r(NULL, " ", &saveptr);
}
cmd.args[i] = NULL;
cmd.argc = i;
return cmd;
}
// 解析管道命令
Pipeline parse_pipeline(char *input) {
Pipeline pipeline;
char *token;
char *saveptr;
int i = 0;
pipeline.commands = (Command *)malloc(10 * sizeof(Command));
if (!pipeline.commands) {
perror("malloc");
exit(EXIT_FAILURE);
}
token = strtok_r(input, "|", &saveptr);
while (token != NULL && i < 9) {
pipeline.commands[i] = parse_command(token);
token = strtok_r(NULL, "|", &saveptr);
i++;
}
pipeline.num_commands = i;
return pipeline;
}
// 执行单个命令
void execute_command(Command cmd) {
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
if (execvp(cmd.args[0], cmd.args) == -1) {
perror("execvp");
exit(EXIT_FAILURE);
}
} else {
int status;
waitpid(pid, &status, 0);
}
}
// 执行管道命令
void execute_pipeline(Pipeline pipeline) {
int pipe_fds[10][2];
int i;
for (i = 0; i < pipeline.num_commands - 1; i++) {
if (pipe(pipe_fds[i]) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < pipeline.num_commands; i++) {
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
if (i > 0) {
if (dup2(pipe_fds[i - 1][0], STDIN_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
if (i < pipeline.num_commands - 1) {
if (dup2(pipe_fds[i][1], STDOUT_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
for (int j = 0; j < pipeline.num_commands - 1; j++) {
close(pipe_fds[j][0]);
close(pipe_fds[j][1]);
}
if (execvp(pipeline.commands[i].args[0], pipeline.commands[i].args) == -1) {
perror("execvp");
exit(EXIT_FAILURE);
}
}
}
for (i = 0; i < pipeline.num_commands - 1; i++) {
close(pipe_fds[i][0]);
close(pipe_fds[i][1]);
}
for (i = 0; i < pipeline.num_commands; i++) {
int status;
wait(NULL);
}
}
int main() {
char input[1024];
printf("Enter command: ");
fgets(input, sizeof(input), stdin);
input[strcspn(input, "\n")] = '\0';
Pipeline pipeline = parse_pipeline(input);
if (pipeline.num_commands == 1) {
execute_command(pipeline.commands[0]);
} else {
execute_pipeline(pipeline);
}
for (int i = 0; i < pipeline.num_commands; i++) {
free(pipeline.commands[i].args);
}
free(pipeline.commands);
return 0;
}