1. 调用外部程序
在go中用os/exec
来调用和执行外部命令,如下,先通过exec.Command
来构建cmd结构体,再cmd.Run()
。
package main
import (
"os/exec"
)
func main() {
cmd := exec.Command("./test")
cmd.Run()
}
2. Terminal里实时输出信息
但是这样调用Terminal里并不会显示./test
程序的输出。我们需要指定一下标准输入输出。
cmd := exec.Command("./test")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
3. 简单获取执行结果
如果外部程序执行时间非常短,几乎不需要等待时,用cmd.CombineOutput()
代替cmd.Run()
即可捕获输出。
cmd := exec.Command("./test")
out, _ = cmd.CombineOutput()
fmt.Print(string(out))
4. 如何执行一个字符串型的命令
exec.Command()
接收的参数是命令行拆开的多个参数,并不是一个字符串。exec.Command("ls -l")
会报错,需要拆开写exec.Command("ls", "-l")
。有一种比较省事的写法,调用sh -c xxx
来执行。如下:
cmd := exec.Command("sh", "-c", cmd_string)
5. Run拆成Start和Wait
默认cmd.Run
会等待外部程序运行结束才返回。我们可以把cmd.Run()
拆成两句cmd.Start()
和cmd.Wait()
。
cmd := exec.Command("sh", "-c", cmd_string)
cmd.Start()
do_someting()
cmd.Wait()
6. 利用goroutine来并行执行
我们先把包一个运行外部命令的函数:
func run_cmd (cmd_string string) {
fmt.Printf("cmd start...\n")
cmd := exec.Command("sh", "-c", cmd_string)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
cmd.Wait()
fmt.Printf("cmd done\n")
}
然后在主程序里內并行运行两个外部程序,并等待60s,待外部程序执行完。
func main(){
go run_cmd("./test1")
go run_cmd("./test2")
time.Sleep(time.Duration(60) * time.Second)
}
这个例子里,强行等待60s并不怎么合理,因为我们通常不知道外部程序到底需要多长时间。
有一种更优雅的方式,用sync.WaitGroup
来同步。启动时waitgroup加一,结束waitgroup减一。wg.Wait()
会一直等,直到wg=0。
package main
import (
"os"
"os/exec"
"sync"
"fmt"
)
var wg sync.WaitGroup
func run_cmd (cmd_string string, id int) {
defer wg.Done()
fmt.Printf("cmd(%d) start...\n", id)
cmd := exec.Command("sh", "-c", cmd_string)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
cmd.Wait()
fmt.Printf("cmd(%d) done\n", id)
}
func main() {
wg.Add(1)
go run_cmd("./test", 1)
wg.Add(1)
go run_cmd("./test", 2)
wg.Wait()
fmt.Println("exit")
}
7. 限制并行的数量
利用channel缓冲区的大小来限制goroutine的并发数量,缓冲区满会阻一塞程序的执行。下面是一个例子:
package main
import (
"os"
"os/exec"
"sync"
"fmt"
)
var wg sync.WaitGroup
var ch = make(chan struct{}, 4)
func run_cmd (cmd_string string, id int) {
defer wg.Done()
fmt.Printf("cmd(%d) start...\n", id)
cmd := exec.Command("sh", "-c", cmd_string)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
cmd.Wait()
fmt.Printf("cmd(%d) done\n", id)
<-ch
}
func main() {
for i:=0; i<10; i++ {
ch <- struct{}{}
wg.Add(1)
go run_cmd("./test", i)
}
wg.Wait()
fmt.Println("exit")
}
参考资料: