You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于fork()与execvp()实现简易Shell:命令执行后程序退出问题求助

解决简易Shell循环运行的问题

嘿,我懂你现在的困扰——写的Shell执行一次命令就直接退出,没法循环接收输入对吧?核心问题就是你的代码缺少一个主循环结构,而且没处理exit指令的退出逻辑。我来给你一步步修改和解释:

完整修改后的代码

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

#define MAX_COMMAND_LENGTH 100
#define MAX_ARGS 10

int main() {
    char cadena[MAX_COMMAND_LENGTH];
    char *argv[MAX_ARGS];
    pid_t pid;

    // 主循环:持续运行直到输入exit或EOF
    while (1) {
        // 输出自定义Shell提示符
        printf("myshell> ");
        fflush(stdout); // 强制刷新输出缓冲,确保提示符立即显示

        // 读取用户输入
        if (fgets(cadena, MAX_COMMAND_LENGTH, stdin) == NULL) {
            // 处理Ctrl+D这类EOF情况
            printf("\n");
            break;
        }

        // 去掉输入末尾的换行符(fgets会把回车读进来)
        cadena[strcspn(cadena, "\n")] = '\0';

        // 判断是否输入exit,触发退出逻辑
        if (strcmp(cadena, "exit") == 0) {
            printf("Exiting myshell...\n");
            break;
        }

        // 将输入的命令行分割成execvp需要的参数数组
        int arg_count = 0;
        argv[arg_count] = strtok(cadena, " ");
        while (argv[arg_count] != NULL && arg_count < MAX_ARGS - 1) {
            arg_count++;
            argv[arg_count] = strtok(NULL, " ");
        }
        argv[arg_count] = NULL; // execvp要求参数数组最后一个元素为NULL

        // 创建子进程执行命令
        pid = fork();
        if (pid == -1) {
            perror("fork failed");
            continue; // 创建失败时跳过本次循环,继续等待下一次输入
        } else if (pid == 0) {
            // 子进程:执行目标命令
            execvp(argv[0], argv);
            // 如果execvp返回,说明命令执行失败
            perror("execvp failed");
            exit(EXIT_FAILURE);
        } else {
            // 父进程:等待子进程结束,避免产生僵尸进程
            wait(NULL);
        }
    }

    return 0;
}

关键修改点说明

  • 主循环while(1):这是让Shell持续运行的核心,只有遇到exit指令或EOF(比如按Ctrl+D)才会跳出循环终止程序。
  • exit指令判断:用strcmp对比输入字符串和"exit",匹配时直接跳出循环,结束Shell。
  • 输入处理优化:用strcspn去掉fgets读取到的换行符,避免多余的换行影响命令执行。
  • 命令参数分割:用strtok把整行输入分割成argv数组,这是execvp要求的参数格式。
  • 父进程等待子进程:通过wait(NULL)让父进程(Shell)等待子进程(执行命令的进程)结束,既不会产生僵尸进程,也能保证命令执行完后才再次显示提示符。
  • 提示符强制刷新:fflush(stdout)解决了输出缓冲导致提示符延迟显示的问题。

额外小提示

如果输入的命令不存在,execvp会返回,子进程会打印错误信息后退出,父进程会继续循环等待下一次输入。后续你还可以扩展处理内置命令(比如cd,因为execvp无法改变父进程的工作目录,需要在父进程中单独处理)、管道等功能,但当前版本已经能满足你“循环运行直到输入exit”的基础需求。

内容的提问来源于stack exchange,提问作者TheAndreyx22

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:18:38