英文:
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
命令似乎会抛出错误。如果我使用cat
或wc
命令,代码就可以正常运行。
有任何想法为什么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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论