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