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

Linux下能否请求运行中Shell执行命令并获输出?C与Bash实现可行吗?

如何让已运行的Shell进程执行命令并获取输出

当然可以实现!不过首先得明确:exec*和system这类函数都是启动新的Shell进程,而新进程完全没有原Shell的状态(比如目录栈dirs、后台任务jobs这些都是Shell进程内部的变量/状态),所以要获取目标Shell的特定状态,必须让正在运行的那个Shell实例来执行命令,这得靠进程间通信(IPC)来实现。

下面分Bash脚本和C语言两种场景来讲解:

一、用Bash实现的简单方案(基于命名管道FIFO)

这是最直接的方式,让目标Shell监听一个管道,接收外部发来的命令并执行,再把输出发回来。

步骤1:在目标Shell中设置IPC通道

先在你想要控制的那个bash里执行以下代码,创建两个命名管道并启动一个后台循环来处理命令:

# 创建命令输入和输出的命名管道
mkfifo /tmp/cmd_pipe /tmp/output_pipe

# 后台循环:读取命令管道的内容,执行后把输出写入输出管道
while true; do
    # 读取命令(如果管道没数据会阻塞等待)
    if read cmd < /tmp/cmd_pipe; then
        # 执行命令,把标准输出和错误都重定向到输出管道
        eval "$cmd" > /tmp/output_pipe 2>&1
    fi
done &

# 记录后台循环的PID,方便后续关闭
echo $! > /tmp/pipe_loop.pid

步骤2:从外部发送命令并获取输出

在另一个终端或者脚本里,你可以这样发送命令并读取结果:

# 发送命令到目标Shell
echo "dirs -v" > /tmp/cmd_pipe

# 读取命令的输出
cat /tmp/output_pipe

注意事项:

  • eval会执行任何传入的命令,所以如果是不可信的命令,会有安全风险,使用时要谨慎。
  • 当不再需要这个通道时,记得清理:kill $(cat /tmp/pipe_loop.pid); rm /tmp/cmd_pipe /tmp/output_pipe /tmp/pipe_loop.pid

二、用C语言实现的方案

原理和Bash版本一致,就是通过FIFO或者Unix域套接字和目标Shell通信。这里以FIFO为例:

1. 目标Shell的准备工作

和上面Bash的步骤1一样,先在目标Shell里创建FIFO并启动处理循环。

2. C程序代码示例

这个程序负责发送命令到FIFO,并读取输出:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define CMD_PIPE "/tmp/cmd_pipe"
#define OUTPUT_PIPE "/tmp/output_pipe"

int main() {
    int cmd_fd, output_fd;
    char cmd[] = "jobs\n"; // 要执行的命令
    char buffer[1024];
    ssize_t bytes_read;

    // 打开命令管道,写入命令
    cmd_fd = open(CMD_PIPE, O_WRONLY);
    if (cmd_fd == -1) {
        perror("Failed to open command pipe");
        exit(EXIT_FAILURE);
    }
    write(cmd_fd, cmd, strlen(cmd));
    close(cmd_fd);

    // 打开输出管道,读取结果
    output_fd = open(OUTPUT_PIPE, O_RDONLY);
    if (output_fd == -1) {
        perror("Failed to open output pipe");
        exit(EXIT_FAILURE);
    }
    while ((bytes_read = read(output_fd, buffer, sizeof(buffer)-1)) > 0) {
        buffer[bytes_read] = '\0';
        printf("Command output:\n%s", buffer);
    }
    close(output_fd);

    return 0;
}

编译运行:

gcc -o shell_cmd shell_cmd.c
./shell_cmd

三、其他可选方案

如果目标Shell运行在screen或tmux会话中,也可以用它们的内置命令发送指令:

  • 比如用screen:
    # 发送命令到名为"my_session"的screen会话
    screen -S my_session -X stuff "dirs -v > /tmp/screen_out\n"
    # 读取输出
    cat /tmp/screen_out
    
  • tmux类似:
    tmux send-keys -t my_session "dirs -v > /tmp/tmux_out" C-m
    cat /tmp/tmux_out
    

为什么不能用exec/system?

再强调一下:exec*函数会替换当前进程为新的Shell,system则是fork一个新进程来运行Shell,这两个新Shell都是独立的,没有原Shell的目录栈、后台任务等状态,所以执行dirs或jobs只能得到空结果或者新Shell的状态,完全不是你想要的目标Shell的信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:10:07