从exec.Command写入文件

时间:2019-07-18 07:23:41

标签: go

我正在尝试将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而不是从该代码执行,我正在获取数据... 我想念什么?

2 个答案:

答案 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方法,然后您可以将程序中的标准输出复制到文件中。