如何使用Go在命令行上执行diff?

时间:2015-03-18 14:51:43

标签: bash go command-line-interface

我在使用Ubuntu 14.04并在命令行上执行diff时遇到问题。请查看以下Go代码:

package main

import "fmt"
import "log"
import "os/exec"

func main() {
    output, err := exec.Command("diff", "-u", "/tmp/revision-1", "/tmp/revision-4").Output()
    if err != nil {
        log.Fatalln(err)
    }

    fmt.Println(string(output))
}

如果我使用go run test.go执行此操作,则会收到以下错误:

2015/03/18 14:39:25 exit status 1
exit status 1

diff出现了问题,它返回1作为退出代码。只有diff命令似乎会抛出错误。如果我使用catwc命令,代码运行正常。

为什么diff在这里不起作用而其他命令有效?

1 个答案:

答案 0 :(得分:5)

使用exec运行程序时,如果退出代码不是0,则会出错。来自doc:

  

如果命令运行,返回的错误为nil,复制stdin,stdout和stderr没有问题,退出时退出状态为零。

     

如果命令无法运行或未成功完成,则错误类型为* ExitError。对于I / O问题,可能会返回其他错误类型。

所以这里发生的是当文件不同时diff会返回错误,但你会把它当成运行时错误。只需更改您的代码即可反映出它不是。可以通过检查错误来实现。

e.g。像这样的东西:

    output, err := exec.Command("diff", "-u", "/tmp/revision-1", "/tmp/revision-4").CombinedOutput()
    if err != nil {

        switch err.(type) {
        case *exec.ExitError:
            // this is just an exit code error, no worries
            // do nothing

        default: //couldnt run diff
            log.Fatal(err)
        }
    }

另外,我已将其更改为CombinedOutput,因此如果发生任何差异特定错误,您也会看到stderr。

注意即使其中一个文件不存在,您也会收到“有效”错误。因此,您可以通过执行以下操作来检查ExitError的退出代码:

    switch e := err.(type) {
    case *exec.ExitError:

        // we can check the actual error code. This is not platform portable 
        if status, ok := e.Sys().(syscall.WaitStatus); ok {
            // exit code 1 means theres a difference and is not an error
            if status.ExitStatus() != 1 { 
                log.Fatal(err)
            }
        }