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

如何用C语言启动持续运行的Bash程序并实现双向交互

如何用C语言启动持续运行的Bash程序并实现双向交互

看起来你需要的是和一个长期运行的外部进程保持双向通信——毕竟每次用system()或者popen()都会重新启动进程,自然会丢失之前的状态。我来给你捋捋具体怎么实现:

核心思路

要实现这种持久的双向交互,我们需要手动创建两个管道:

  • 输入管道:父进程写,子进程读,重定向为子进程的标准输入(用来给L发指令)
  • 输出管道:子进程写,父进程读,重定向为子进程的标准输出(用来读取L的响应)
    然后通过fork()创建子进程,用exec()系列函数启动你的Bash程序L,同时在父进程里通过这两个管道持续收发数据。

完整代码示例

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

#define BUFFER_SIZE 1024

// 封装一个发送数据并读取响应的工具函数
int send_and_receive(int write_fd, int read_fd, const char* send_msg, char* response) {
    // 发送数据,注意加换行(多数交互式程序是行缓冲,需要换行才会处理输入)
    if (write(write_fd, send_msg, strlen(send_msg)) == -1) {
        perror("Failed to write to pipe");
        return -1;
    }
    if (write(write_fd, "\n", 1) == -1) {
        perror("Failed to send newline trigger");
        return -1;
    }

    // 读取响应,这里简单实现单次读取,长响应可以循环读取直到EOF
    ssize_t bytes_read = read(read_fd, response, BUFFER_SIZE - 1);
    if (bytes_read == -1) {
        perror("Failed to read from pipe");
        return -1;
    }
    response[bytes_read] = '\0'; // 确保字符串以空字符结尾
    return 0;
}

int main() {
    int parent_to_child[2]; // 父写子读的输入管道
    int child_to_parent[2]; // 子写父读的输出管道
    pid_t pid;
    char buffer[BUFFER_SIZE];

    // 创建两个管道,失败则直接退出
    if (pipe(parent_to_child) == -1 || pipe(child_to_parent) == -1) {
        perror("Failed to create communication pipes");
        exit(EXIT_FAILURE);
    }

    // 分叉出子进程
    pid = fork();
    if (pid == -1) {
        perror("Failed to fork child process");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        // 子进程逻辑:重定向标准IO到管道,启动目标程序L
        // 关闭不需要的管道端(必须做,否则会导致阻塞)
        close(parent_to_child[1]);
        close(child_to_parent[0]);

        // 重定向子进程的标准输入到输入管道的读端
        if (dup2(parent_to_child[0], STDIN_FILENO) == -1) {
            perror("Failed to redirect stdin");
            exit(EXIT_FAILURE);
        }
        // 重定向子进程的标准输出到输出管道的写端
        if (dup2(child_to_parent[1], STDOUT_FILENO) == -1) {
            perror("Failed to redirect stdout");
            exit(EXIT_FAILURE);
        }

        // 关闭已经重定向完成的管道原文件描述符
        close(parent_to_child[0]);
        close(child_to_parent[1]);

        // 启动目标程序L,如果L不在系统PATH里,要写绝对路径
        execlp("L", "L", (char*)NULL);
        // 如果exec函数返回,说明启动失败
        perror("Failed to launch program L");
        exit(EXIT_FAILURE);
    } else {
        // 父进程逻辑:通过管道和子进程交互
        // 关闭不需要的管道端
        close(parent_to_child[0]);
        close(child_to_parent[1]);

        // 第一次交互:发送"Hello Program",获取响应
        printf("Sending: Hello Program\n");
        if (send_and_receive(parent_to_child[1], child_to_parent[0], "Hello Program", buffer) == 0) {
            printf("Received: %s", buffer);
        }

        // 第二次交互:发送"What did I send you",获取响应
        printf("\nSending: What did I send you\n");
        if (send_and_receive(parent_to_child[1], child_to_parent[0], "What did I send you", buffer) == 0) {
            printf("Received: %s", buffer);
        }

        // 发送退出指令(如果L支持exit命令),或者直接终止子进程
        write(parent_to_child[1], "exit\n", 5);
        // 等待子进程正常结束
        waitpid(pid, NULL, 0);

        // 关闭剩余的管道端
        close(parent_to_child[1]);
        close(child_to_parent[0]);
    }

    return 0;
}

必看注意事项

  • 管道端的关闭:一定要关闭不需要的管道端!否则会导致进程在read()或write()时无限阻塞——只有当管道的所有端都关闭时,才会触发EOF信号。
  • 缓冲问题:绝大多数交互式程序(包括Bash脚本)默认是行缓冲模式,所以发送数据必须加换行符\n,否则程序会一直等待输入结束。如果你的L是全缓冲模式,可以用stdbuf工具关闭缓冲:把execlp的启动命令改成execlp("stdbuf", "stdbuf", "-i0", "-o0", "L", (char*)NULL);
  • 错误处理:示例只做了基础的错误检测,实际使用时可以增强逻辑,比如通过waitpid()监控子进程是否意外崩溃,或者处理长响应的循环读取。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:38:09