简易shell

点击查看代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/select.h>

#define MAX_INPUT_LEN   1024
#define MAX_ARGS        64
#define READ_BUF_SIZE   4096
#define PIPE_READ       0
#define PIPE_WRITE      1
#define STDIN_FD        STDIN_FILENO
#define STDOUT_FD       STDOUT_FILENO
#define SELECT_ERROR    (-1)
#define CHILD_PROCESS   (0)

int split_input(char *line, char **args) {
    int count = 0;
    char *token = strtok(line, " \t\n");

    while ((token != NULL) && (count < (MAX_ARGS - 1))) {
        args[count] = token;
        count++;
        token = strtok(NULL, " \t\n");
    }
    args[count] = NULL;
    return count;
}

int main() {
    char input[MAX_INPUT_LEN] = {0};
    char *args[MAX_ARGS] = {NULL};

    while (1) {
        printf("mysh> ");
        fflush(stdout);

        if (fgets(input, sizeof(input), stdin) == NULL) {
            break;
        }

        input[strcspn(input, "\n")] = '\0';

        if (strcmp(input, "exit") == 0) {
            break;
        }

        int arg_count = split_input(input, args);
        if (arg_count == 0) {
            continue;
        }

        int pipefd[2] = {-1, -1};
        if (pipe(pipefd) == -1) {
            perror("pipe");
            continue;
        }

        pid_t pid = fork();
        if (pid == -1) {
            perror("fork");
            close(pipefd[PIPE_READ]);
            close(pipefd[PIPE_WRITE]);
            continue;
        }

        if (pid == CHILD_PROCESS) {
            close(pipefd[PIPE_READ]);
            dup2(pipefd[PIPE_WRITE], STDOUT_FD);
            close(pipefd[PIPE_WRITE]);

            execvp(args[0], args);
            perror("execvp");
            exit(EXIT_FAILURE);
        } else {
            close(pipefd[PIPE_WRITE]);
            fd_set readfds;
            int max_fd = (pipefd[PIPE_READ] > STDIN_FD) ? 
                         (pipefd[PIPE_READ] + 1) : 
                         (STDIN_FD + 1);
            char buffer[READ_BUF_SIZE] = {0};
            int stop_requested = 0;

            while (1) {
                FD_ZERO(&readfds);
                FD_SET(pipefd[PIPE_READ], &readfds);
                FD_SET(STDIN_FD, &readfds);

                if (select(max_fd, &readfds, NULL, NULL, NULL) == SELECT_ERROR) {
                    perror("select");
                    break;
                }

                if (FD_ISSET(STDIN_FD, &readfds)) {
                    char cmd[MAX_INPUT_LEN] = {0};
                    if (fgets(cmd, sizeof(cmd), stdin) == NULL) {
                        break;
                    }
                    cmd[strcspn(cmd, "\n")] = '\0';

                    if (strcmp(cmd, "stop") == 0) {
                        kill(pid, SIGKILL);
                        waitpid(pid, NULL, 0);
                        stop_requested = 1;
                        printf("Command terminated by user.\n");
                        break;
                    }
                }

                if (FD_ISSET(pipefd[PIPE_READ], &readfds)) {
                    ssize_t bytes = read(pipefd[PIPE_READ], buffer, sizeof(buffer) - 1);
                    if (bytes <= 0) {
                        break;
                    }
                    buffer[bytes] = '\0';
                    printf("%s", buffer);
                }
            }

            close(pipefd[PIPE_READ]);
            if (!stop_requested) {
                waitpid(pid, NULL, 0);
            }
        }
    }
    return EXIT_SUCCESS;
}

点击查看代码

/*  mysh.c  */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>

#define MAX_INPUT_LEN   1024
#define MAX_ARGS        64
#define READ_BUF_SIZE   4096

/* ---------- 工具函数 ---------- */
static void die(const char *msg)
{
    perror(msg);
    exit(EXIT_FAILURE);
}

static int split_input(char *line, char **argv)
{
    int argc = 0;
    for (char *tok = strtok(line, " \t\n"); tok && argc < MAX_ARGS - 1; tok = strtok(NULL, " \t\n"))
        argv[argc++] = tok;
    argv[argc] = NULL;
    return argc;
}

/* ---------- 子进程执行 ---------- */
static void run_child(char *const argv[])
{
    execvp(argv[0], argv);
    die("execvp");
}

/* ---------- 父进程读取/监控 ---------- */
static void relay_output_and_wait(int pipe_out, pid_t child)
{
    fd_set rfds;
    char buf[READ_BUF_SIZE];
    int child_done = 0;

    while (!child_done) {
        FD_ZERO(&rfds);
        FD_SET(STDIN_FILENO, &rfds);
        FD_SET(pipe_out, &rfds);

        int maxfd = (pipe_out > STDIN_FILENO ? pipe_out : STDIN_FILENO) + 1;
        if (select(maxfd, &rfds, NULL, NULL, NULL) == -1) {
            if (errno == EINTR) continue;
            perror("select");
            break;
        }

        /* 用户输入:仅处理 stop 命令 */
        if (FD_ISSET(STDIN_FILENO, &rfds)) {
            char line[MAX_INPUT_LEN];
            if (!fgets(line, sizeof(line), stdin))
                break;
            if (strncmp(line, "stop", 4) == 0) {
                kill(child, SIGKILL);
                waitpid(child, NULL, 0);
                puts("Command terminated by user.");
                return;
            }
        }

        /* 子进程输出 */
        if (FD_ISSET(pipe_out, &rfds)) {
            ssize_t n = read(pipe_out, buf, sizeof(buf) - 1);
            if (n <= 0) {
                child_done = 1;
            } else {
                buf[n] = '\0';
                fputs(buf, stdout);
                fflush(stdout);
            }
        }
    }

    /* 正常结束 */
    close(pipe_out);
    waitpid(child, NULL, 0);
}

/* ---------- 主循环 ---------- */
static void shell_loop(void)
{
    char input[MAX_INPUT_LEN];
    char *argv[MAX_ARGS];

    while (1) {
        printf("mysh> ");
        fflush(stdout);

        if (!fgets(input, sizeof(input), stdin))        /* EOF (Ctrl-D) */
            break;

        input[strcspn(input, "\n")] = '\0';
        if (strcmp(input, "exit") == 0)
            break;

        int argc = split_input(input, argv);
        if (argc == 0)
            continue;

        int pipefd[2];
        if (pipe(pipefd) == -1) {
            perror("pipe");
            continue;
        }

        pid_t pid = fork();
        if (pid == -1) {
            perror("fork");
            close(pipefd[0]);
            close(pipefd[1]);
            continue;
        }

        if (pid == 0) {                /* child */
            close(pipefd[0]);          /* 关闭读端 */
            dup2(pipefd[1], STDOUT_FILENO);
            close(pipefd[1]);
            run_child(argv);
        } else {                       /* parent */
            close(pipefd[1]);          /* 关闭写端 */
            relay_output_and_wait(pipefd[0], pid);
        }
    }
}

int main(void)
{
    shell_loop();
    return EXIT_SUCCESS;
}

posted @ 2025-08-07 14:34  balan学嵌入式  阅读(7)  评论(0)    收藏  举报