我正在尝试将bash命令中的文件写入Go中的文件。 请注意,在这里使用Go over bash的原因有很多:我有更多的逻辑,例如解析配置文件,我想并行地为多个DB运行该代码,并在此之后最终执行一些更复杂的数据操作。
dumpStr := fmt.Sprintf("pg_dump -U %s -h %s %s | gzip", DbUserName, DbHost, DbName)
cmd := exec.Command("bash", "-c", dumpStr)
cmd.Env = append(cmd.Env, "PGPASSWORD="+DbPassword)
outfile, err := os.Create(DbName + ".gz")
if err != nil {
panic(err)
}
outfile = cmd.Stdout
defer outfile.Close()
err = cmd.Start()
if err != nil {
panic(err)
}
cmd.Wait()
但是,我得到的结果是空的。
如果我从CLI执行dumpStr
而不是从该代码执行,我正在获取数据...
我想念什么?
答案 0 :(得分:3)
正如Flimzy所说,您没有捕获pg_dump
的输出。您可以使用Go执行此操作,也可以使用pg_dump
-s --file
。它还可以使用--compress
进行压缩,因此无需通过管道传输到gzip
。这样就不需要bash了,并且可以避免shell引用问题。
cmd := exec.Command(
"pg_dump",
"--compress=9",
"--file="+DbName + ".gz",
"-U"+DbUserName,
"-h"+DbHost,
DbName,
)
log.Print("Running pg_dump...")
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
更简单,更安全。
为便于说明,以下是您在Go中的全部操作。
使用 Cmd.StdoutPipe
将开放的IO阅读器获取到pg_dump
的标准输出中。然后使用io.Copy
从标准输出复制到打开的文件。
@Peter指出,自Cmd.Stdout
is an io.Reader以来,将打开的文件分配给cmd.Stdout
并让cmd
直接写入它更为简单。
// Same as above, but no --file.
cmd := exec.Command(
"pg_dump",
"--compress=9",
"-U"+DbUserName,
"-h"+DbHost,
DbName,
)
// Open the output file
outfile, err := os.Create(DbName + ".gz")
if err != nil {
log.Fatal(err)
}
defer outfile.Close()
// Send stdout to the outfile. cmd.Stdout will take any io.Writer.
cmd.Stdout = outfile
// Start the command
if err = cmd.Start(); err != nil {
log.Fatal(err)
}
log.Print("Waiting for command to finish...")
// Wait for the command to finish.
if err = cmd.Wait(); err != nil {
log.Fatal(err)
}
此外,您仅检查命令是否已启动,而不是命令是否成功运行。
来自Cmd.Start
的文档。
启动将启动指定的命令,但不等待其完成。
一旦命令退出,Wait方法将返回退出代码并释放关联的资源。
您正在检查cmd.Start
是否有错误,但没有检查cmd.Wait
。检查cmd.Start
中的错误仅表示命令已启动。如果程序运行时出现错误,您将不知道它是什么。
答案 1 :(得分:2)
您需要实际使用命令的输出。你没那么做为此,请使用StdoutPipe
方法,然后您可以将程序中的标准输出复制到文件中。