
本文介绍如何在 Go 程序中不依赖临时脚本文件,直接向 mongo(或现代 mongosh)进程传入多行 JavaScript 命令,利用 exec.Command 的 Stdin 字段实现命令链式执行。
本文介绍如何在 go 程序中不依赖临时脚本文件,直接向 `mongo`(或现代 `mongosh`)进程传入多行 javascript 命令,利用 `exec.command` 的 stdin 字段实现命令链式执行。
在 Go 中调用外部 shell 命令时,常见的误区是将 MongoDB 的交互式命令(如 use test-db、db.user.remove({...}))当作独立进程连续执行。实际上,mongo 是一个 REPL(读取-求值-打印循环)解释器,它启动后会持续从标准输入(stdin)读取并执行命令,直到输入流结束或显式退出。因此,“链式执行”的本质不是启动多个进程,而是向单个 mongo 进程的 stdin 写入完整的命令序列。
正确做法是:使用 exec.Command 启动 mongo 进程,并将其 Stdin 字段设置为一个实现了 io.Reader 接口的数据源(例如 strings.NewReader),从而将命令字符串一次性注入其输入流。
以下是一个完整、可运行的示例:
package main
import (
"fmt"
"os/exec"
"strings"
)
func main() {
// 构造要执行的 MongoDB 命令脚本(支持多行)
script := `
use test-db
db.user.remove({"id": 1})
`
// 启动 mongo 进程,指定数据库名作为参数(等价于 mongo test-db)
cmd := exec.Command("mongo", "test-db")
// 将命令脚本绑定到 stdin(注意:末尾换行可提升兼容性)
cmd.Stdin = strings.NewReader(strings.TrimSpace(script) + "\n")
// 捕获标准输出和标准错误(强烈建议!便于调试)
cmd.Stdout = nil // 可设为 os.Stdout 查看输出
cmd.Stderr = nil // 可设为 os.Stderr 查看错误
// 执行并等待完成
err := cmd.Run()
if err != nil {
fmt.Printf("Mongo 命令执行失败: %v\n", err)
return
}
fmt.Println("Mongo 命令执行成功")
}⚠️ 重要注意事项:
mongo 已弃用,推荐迁移到 mongosh:自 MongoDB 6.0 起,官方已弃用 mongo shell,推荐使用功能更完善、安全性更高的 mongosh。若已安装 mongosh,只需将 exec.Command("mongo", ...) 替换为 exec.Command("mongosh", ...),其余逻辑完全兼容。
命令必须合法且可被 MongoDB Shell 解析:确保 JSON 格式正确(如双引号需转义)、语法符合当前 MongoDB 版本的 Shell 规范;避免使用交互式命令(如 exit 或 quit),除非明确需要提前终止。
-
错误排查依赖 Stderr:MongoDB 在执行失败时(如数据库不存在、权限不足、语法错误)通常将错误信息写入 stderr。生产环境中务必捕获并检查 cmd.Stderr,例如:
var stderr strings.Builder cmd.Stderr = &stderr // ... cmd.Run() if err != nil { fmt.Printf("错误详情: %s\n", stderr.String()) } 不支持“交互式状态延续”以外的复杂控制流:该方法适用于顺序执行脚本,但无法实现条件判断、循环或动态响应(如根据上一条结果决定下一条命令)。如需复杂逻辑,请改用 MongoDB 官方 Go 驱动(go.mongodb.org/mongo-driver/mongo)直接操作数据库。
总结来说,Go 中“链式执行 shell 命令”的关键在于理解进程 I/O 模型——不是启动多个命令,而是向单一解释器进程的 stdin 注入完整指令流。借助 strings.NewReader 和 exec.Cmd.Stdin,即可优雅、安全、无临时文件地完成 MongoDB 初始化与数据清理等自动化任务。


















