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

huangapple go评论78阅读模式
英文:

How to execute diff on the command line using Go?

问题

我在使用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在这里不起作用,而其他命令可以正常工作吗?

英文:

I'm having a problem using Ubuntu 14.04 and executing diff on the command line. Look at the following Go code:

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))
}

If i execute this using go run test.go i get the following error:

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

So something is going wrong with diff and it's returning 1 as its exit code. Only the diff command seems to throw an error. If i use the cat or wc command, the code runs fine.

Any ideas why diff doesn't work here but other commands do?

答案1

得分: 6

当你使用exec运行程序时,如果退出代码不为0,你会得到一个错误。根据文档:

> 如果命令运行正常,没有问题地复制stdin、stdout和stderr,并以零退出状态退出,则返回的错误为nil。
>
> 如果命令运行失败或未成功完成,错误类型为*ExitError。其他错误类型可能由于I/O问题而返回。

所以这里的情况是,当文件不同时,diff返回一个错误,但你把它当作运行时错误处理。只需更改代码以反映它不是运行时错误。可以通过检查错误来实现。

例如,像这样:

    output, err := exec.Command("diff", "-u", "/tmp/revision-1", "/tmp/revision-4").CombinedOutput()
    if err != nil {
           
        switch err.(type) {
        case *exec.ExitError:
            // 这只是一个退出代码错误,不用担心
            // 什么都不做

        default: //无法运行diff
            log.Fatal(err)
        }
    }

另外,我已经更改了它以获取CombinedOutput,这样如果发生任何特定于diff的错误,你将看到stderr。

注意,即使其中一个文件不存在,你也会得到一个“有效”的错误。因此,你可以通过以下方式检查ExitError的退出代码:

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

        // 我们可以检查实际的错误代码。这不是平台可移植的
        if status, ok := e.Sys().(syscall.WaitStatus); ok {
            // 退出代码1表示存在差异,不是错误
            if status.ExitStatus() != 1 { 
                log.Fatal(err)
            }
        }
英文:

When you run a program with exec, you get an error if the exit code was not 0. From the doc:

> The returned error is nil if the command runs, has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
>
> If the command fails to run or doesn't complete successfully, the error is of type *ExitError. Other error types may be returned for I/O problems.

So what happens here is that diff returns an error when the files are different, yet you treat it like a runtime error. Just change your code to reflect that it isn't. It's possible by checking the error.

e.g. something like this:

    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)
        }
    }

Also, I've changed it get CombinedOutput, so if any diff specific errors occured, you'll see stderr as well.

Note that you'll get a "valid" error even if one of the files doesn't exist. So you can check the ExitError's exit code by doing something like this:

    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)
            }
        }

huangapple
  • 本文由 发表于 2015年3月18日 22:51:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/29125248.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定