全栈应用服务器

  • 全栈应用服务器 > SDK 下载 > Go SDK 概览 > 命令执行

    命令执行

    最近更新时间: 2026-03-05 19:04:48

    命令执行

    通过 sb.Commands() 在沙箱内执行终端命令,就像在真实的 Linux 终端中一样。支持同步/异步执行、流式输出、后台进程管理。

    前置条件:请先完成客户端初始化创建沙箱

    同步执行命令

    result, err := sb.Commands().Run(ctx, "echo hello world")
    if err != nil {
    	log.Fatalf("执行命令失败: %v", err)
    }
    fmt.Printf("退出码: %d\n", result.ExitCode)
    fmt.Printf("stdout: %s", result.Stdout)
    fmt.Printf("stderr: %s", result.Stderr)
    

    CommandResult 包含以下字段:

    字段 类型 说明
    ExitCode int 进程退出码
    Stdout string 标准输出
    Stderr string 标准错误输出
    Error string 错误信息

    命令选项

    通过 CommandOption 自定义命令行为:

    result, err := sb.Commands().Run(ctx, "echo $MY_VAR",
    	sandbox.WithEnvs(map[string]string{"MY_VAR": "hello"}),
    	sandbox.WithCwd("/tmp"),
    	sandbox.WithTimeout(5*time.Second),
    )
    
    选项 说明
    WithEnvs(map[string]string) 设置环境变量
    WithCwd(string) 设置工作目录
    WithCommandUser(string) 设置执行用户(默认 user
    WithTag(string) 设置进程标签,方便后续识别
    WithOnStdout(func([]byte)) stdout 实时回调
    WithOnStderr(func([]byte)) stderr 实时回调
    WithTimeout(time.Duration) 命令超时时间

    流式输出

    通过回调函数实时接收标准输出和错误输出,适用于长时间运行的命令。

    result, err := sb.Commands().Run(ctx, "for i in 1 2 3; do echo line-$i; sleep 1; done",
    	sandbox.WithOnStdout(func(data []byte) {
    		fmt.Printf("[stdout] %s", string(data))
    	}),
    	sandbox.WithOnStderr(func(data []byte) {
    		fmt.Printf("[stderr] %s", string(data))
    	}),
    )
    

    后台命令

    启动后台命令

    使用 Start 启动不阻塞主程序的后台命令。

    handle, err := sb.Commands().Start(ctx, "sleep 30", sandbox.WithTag("bg-task"))
    if err != nil {
    	log.Fatalf("启动后台命令失败: %v", err)
    }
    
    // 等待 PID 分配
    pid, err := handle.WaitPID(ctx)
    if err != nil {
    	log.Fatalf("等待 PID 失败: %v", err)
    }
    fmt.Printf("后台命令 PID: %d\n", pid)
    

    等待命令完成

    handle, err := sb.Commands().Start(ctx, "echo done")
    if err != nil {
    	log.Fatalf("启动命令失败: %v", err)
    }
    
    result, err := handle.Wait()
    if err != nil {
    	log.Fatalf("等待命令失败: %v", err)
    }
    fmt.Printf("退出码: %d, stdout: %s", result.ExitCode, result.Stdout)
    

    列出运行中的进程

    processes, err := sb.Commands().List(ctx)
    if err != nil {
    	log.Fatalf("列出进程失败: %v", err)
    }
    for _, p := range processes {
    	tag := "<none>"
    	if p.Tag != nil {
    		tag = *p.Tag
    	}
    	fmt.Printf("PID: %d, 命令: %s, 标签: %s\n", p.PID, p.Cmd, tag)
    }
    

    ProcessInfo 包含以下字段:

    字段 类型 说明
    PID uint32 进程 ID
    Tag *string 进程标签
    Cmd string 命令
    Args []string 命令参数
    Envs map[string]string 环境变量
    Cwd *string 工作目录

    终止进程

    if err := sb.Commands().Kill(ctx, handle.PID()); err != nil {
    	log.Fatalf("终止命令失败: %v", err)
    }
    

    也可以通过 CommandHandle 直接终止:

    if err := handle.Kill(ctx); err != nil {
    	log.Fatalf("终止命令失败: %v", err)
    }
    

    发送标准输入

    向运行中的进程发送数据到标准输入。

    if err := sb.Commands().SendStdin(ctx, handle.PID(), []byte("input data\n")); err != nil {
    	log.Fatalf("发送 stdin 失败: %v", err)
    }
    

    连接到已有进程

    连接到已经在运行的进程,获取其输出流。

    handle, err := sb.Commands().Connect(ctx, pid)
    if err != nil {
    	log.Fatalf("连接进程失败: %v", err)
    }
    result, err := handle.Wait()
    

    CommandHandle 方法

    方法 说明
    PID() uint32 返回进程 ID
    Wait() (*CommandResult, error) 等待命令完成并返回结果
    Kill(ctx) error 终止命令
    WaitPID(ctx) (uint32, error) 等待 PID 分配(用于后台命令启动后)

    完整示例

    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"os"
    	"time"
    
    	"github.com/qiniu/go-sdk/v7/sandbox"
    )
    
    func main() {
    	c, err := sandbox.NewClient(&sandbox.Config{
    		APIKey:   os.Getenv("QINIU_API_KEY"),
    		Endpoint: os.Getenv("QINIU_SANDBOX_API_URL"),
    	})
    	if err != nil {
    		log.Fatalf("创建客户端失败: %v", err)
    	}
    
    	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    	defer cancel()
    
    	timeout := int32(120)
    	sb, _, err := c.CreateAndWait(ctx, sandbox.CreateParams{
    		TemplateID: "base",
    		Timeout:    &timeout,
    	}, sandbox.WithPollInterval(2*time.Second))
    	if err != nil {
    		log.Fatalf("创建沙箱失败: %v", err)
    	}
    	defer sb.Kill(context.Background())
    
    	// 同步执行
    	result, err := sb.Commands().Run(ctx, "echo hello world")
    	if err != nil {
    		log.Fatalf("执行命令失败: %v", err)
    	}
    	fmt.Printf("stdout: %s", result.Stdout)
    
    	// 带环境变量
    	result, err = sb.Commands().Run(ctx, "echo $MY_VAR",
    		sandbox.WithEnvs(map[string]string{"MY_VAR": "sandbox-value"}),
    	)
    	if err != nil {
    		log.Fatalf("执行命令失败: %v", err)
    	}
    	fmt.Printf("stdout: %s", result.Stdout)
    
    	// 指定工作目录
    	result, err = sb.Commands().Run(ctx, "pwd", sandbox.WithCwd("/tmp"))
    	if err != nil {
    		log.Fatalf("执行命令失败: %v", err)
    	}
    	fmt.Printf("stdout: %s", result.Stdout)
    
    	// 流式输出
    	_, err = sb.Commands().Run(ctx, "echo out-line && echo err-line >&2",
    		sandbox.WithOnStdout(func(data []byte) { fmt.Printf("[stdout] %s", string(data)) }),
    		sandbox.WithOnStderr(func(data []byte) { fmt.Printf("[stderr] %s", string(data)) }),
    	)
    	if err != nil {
    		log.Fatalf("流式命令失败: %v", err)
    	}
    
    	// 后台命令
    	handle, err := sb.Commands().Start(ctx, "sleep 10", sandbox.WithTag("bg"))
    	if err != nil {
    		log.Fatalf("启动后台命令失败: %v", err)
    	}
    	pid, err := handle.WaitPID(ctx)
    	if err != nil {
    		log.Fatalf("等待 PID 失败: %v", err)
    	}
    	fmt.Printf("后台命令 PID: %d\n", pid)
    
    	// 列出进程
    	processes, err := sb.Commands().List(ctx)
    	if err != nil {
    		log.Fatalf("列出进程失败: %v", err)
    	}
    	fmt.Printf("运行中的进程: %d 个\n", len(processes))
    
    	// 终止后台命令
    	sb.Commands().Kill(ctx, handle.PID())
    }
    
    以上内容是否对您有帮助?