go语言调用外部程序,并获取外部程序的返回值。
例子1: 程序返回0
$ cat main.go
package main
import (
"fmt"
"os/exec"
)
func main() {
cmd := exec.Command("test.sh")
err := cmd.Run()
if err != nil {
fmt.Printf("Return error: %s\n", err)
} else {
fmt.Printf("Return OK\n")
}
}
$ cat test.sh
#!/bin/bash
echo "Hello"
exit 0
运行结果
$ go build && ./main
Return OK
例子2:程序返回非零
$ cat test.sh
#!/bin/bash
echo "Hello"
exit 2
运行结果
$ go build && ./main
Return error: exit status 2
这里我们看到com.Run()的返回成功还是失败的区分是子程序返回值是否为零,其实在这个例子中子程序test.sh执行是正确的,返回2是希望的行为,但是com.Run()把它定义为错误,go就这么设计的,那就没有办法了,需要注意一下就行了。
例子3:区分正常的程序返回值,还是异常错误
例如子程序test.sh不存在,或者test.sh不可执行:
$ ./main
Return error: exec: "test.sh": executable file not found in $PATH
或者test.sh 收到异常信号crash了。
$ ./main
Return error: signal: killed
改造后的main.go
package main
import (
"fmt"
"syscall"
"os/exec"
)
func main() {
cmd := exec.Command("test.sh")
err := cmd.Run();
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
status := exitErr.Sys().(syscall.WaitStatus)
switch {
case status.Exited():
fmt.Printf("Return exit error: exit code=%d\n", status.ExitStatus())
case status.Signaled():
fmt.Printf("Return exit error: signal code=%d\n", status.Signal())
}
} else {
fmt.Printf("Return other error: %s\n", err)
}
} else {
fmt.Printf("Return OK\n")
}
}
场景1: 正常退出0
$ cat test.sh
#!/bin/bash
echo "Hello"
exit 0
$ ./main
Return OK
子程序正常运行结束,并返回0值。
场景2: 正常退出100
$ cat test.sh
#!/bin/bash
echo "Hello"
exit 100
$ ./main
Return exit error: exit code=100
子程序正常运行结束,并返回100值。
场景3:test.sh不存在或者不可执行
$ chmod -x test.sh
$ ./main
Return other error: exec: "test.sh": executable file not found in $PATH
子程序无法运行,我们得到的是其他类型的错误,而不是exec.ExitError类型错误。
场景4: test.sh 运行中被kill -9
$ cat test.sh
#!/bin/bash
echo "Hello"
sleep 100
exit 100
$ ./main
Return exit error: signal code=9
返回exec.ExitError类型错误,我们拿到signal值为9
注意在另一个Terminal中kill掉test.sh
$ kill -9 PID_OF_test.sh