MST
星途 面试题库

面试题:C语言构建自定义命令执行系统

假设你要在C语言中构建一个简单的命令执行系统,该系统能解析用户输入的命令(例如`echo hello`、`cd /tmp`等),并能处理简单的管道操作(如`ls -l | grep test`)。要求自行设计数据结构来存储命令和参数,实现命令执行的核心逻辑,同时考虑错误处理和内存管理。请阐述设计思路并编写核心代码。
46.5万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 数据结构设计
    • 设计一个结构体来存储单个命令及其参数。例如:
    typedef struct {
        char **args;
        int argc;
    } Command;
    
    • 对于管道操作,使用一个数组来存储多个Command结构体。
    typedef struct {
        Command *commands;
        int num_commands;
    } Pipeline;
    
  2. 命令解析
    • 使用strtok函数或更复杂的词法分析方法将用户输入的字符串按空格等分隔符拆分成命令和参数。
    • 对于管道操作,按|符号拆分字符串,将每个部分分别解析为单个命令。
  3. 命令执行
    • 使用forkexecvp函数来执行每个命令。
    • 对于管道操作,利用pipe函数创建管道,在不同进程间传递数据。
  4. 错误处理
    • forkexecvppipe等函数调用后检查返回值,处理相应的错误,如内存分配失败、命令不存在等。
  5. 内存管理
    • 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;
}