I'm trying to run a shell script from my go program. I want to start up a mongo
instance and then remove some data. So the shell script would look something like this:
mongo
use test-db
db.user.remove({"id": 1})
I initially tried just using the exec.Command
package but it doesn't chain the commands so the mongo db closes and I can't run the other commands:
cmd := exec.Command("mongo", "test-db")
cmd.Start()
cmd1 := exec.Command("db.remove({\"id\": 1})")
cmd1.Run()
cmd.Wait()
The next thing I tried is creating a variable and trying to execute that via sh:
var script = `
#!/bin/bash
mongo
use test-db
db.user.remove({"id": 1})
`
and executing exec.Command("sh", script)
I know I can create a .sh
file but I don't want to do that is there any way to chain commands in go so the mongo db doesn't close and I can execute the other commands?
You seem to misunderstand how processes (such as interpreters and shells, including—it appears—mongodb
as well) work with their so-called standard streams: while the "test-db" is indeed an argument to pass to a mongodb
process to be created on its command-line, the db.user.remove({"id": 1})
is the text that spawned mongodb
instance is supposed to read from its standard input stream.
So basically you need this:
import (
"os/exec"
"strings"
)
cmd := exec.Command("mongo", "test-db")
cmd.Stdin = strings.NewReader(`db.user.remove({"id": 1})
`)
err := cmd.Run()
// Check for an error
To explain how this works, let's cite the manual:
Stdin
specifies the process's standard input.
IfStdin
isnil
, the process reads from the null device (os.DevNull
).
IfStdin
is an*os.File
, the process's standard input is connected directly to that file.
Otherwise, during the execution of the command a separate goroutine reads fromStdin
and delivers that data to the command over a pipe. In this case,Wait
does not complete until the goroutine stops copying, either because it has reached the end ofStdin
(EOF or a read error) or because writing to the pipe returned an error.Stdin io.Reader
So basically you create an object which takes a string and provides something implementing io.Reader
and "wire" it to the standard input of the process about to be created. Once the process starts, os/exec
will make sure to spawn a goroutine which will shovel data between your string and the running mongodb
instance—as if you would start mongodb
by hand and typed that string onto its standard input stream directly.
Note that you also might need to check what mongodb
generates on its standard output streams—especially stderr
,—because if it encounters any errors while executing the script you have submitted to it, it will likely report them there.