我想运行一个命令并从stdout
打印每一行(因为它可用)。此外,如果命令在N秒内没有完成,我也想终止它。
在golang中有一些实现超时的例子(特别是Terminating a Process Started with os/exec in Golang)。我在time.After()
中有一个select
子句,我期望在2秒后命中,此时RunTraceroute
应返回 - 但这不会发生。
我的代码位于下方(并在操场上:http://play.golang.org/p/D4AcoaweMt)
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"time"
)
func RunTraceroute(host string) {
errch := make(chan error, 1)
cmd := exec.Command("/usr/bin/traceroute", host)
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
go func() {
errch <- cmd.Wait()
}()
select {
case <-time.After(time.Second * 2):
log.Println("Timeout hit..")
return
case err := <-errch:
if err != nil {
log.Println("traceroute failed:", err)
}
default:
for _, char := range "|/-\\" {
fmt.Printf("\r%s...%c", "Running traceroute", char)
time.Sleep(100 * time.Millisecond)
}
scanner := bufio.NewScanner(stdout)
fmt.Println("")
for scanner.Scan() {
line := scanner.Text()
log.Println(line)
}
}
}
func main() {
RunTraceroute(os.Args[1])
}
输出(剪掉本地IP地址和网关的前几行):
$ go run pipe.go xinhua.com
Running traceroute...\
2016/04/01 11:16:43 traceroute to xinhua.com (58.64.200.76), 30 hops max, 60 byte packets
.......
.......
.....More deleted lines.....
2016/04/01 11:16:49 12 * * *
2016/04/01 11:16:49 13 4.68.63.214 (4.68.63.214) 3.208 ms 3.176 ms 3.241 ms
2016/04/01 11:16:49 14 * * *
2016/04/01 11:16:49 15 if-ae-9-2.tcore1.TV2-Tokyo.as6453.net (180.87.180.18) 160.314 ms 158.837 ms 161.438 ms
2016/04/01 11:16:49 16 if-ae-5-7.tcore1.HK2-Hong-Kong.as6453.net (180.87.112.189) 157.497 ms if-ae-3-2.tcore1.HK2-Hong-Kong.as6453.net (180.87.112.5) 161.397 ms if-ae-5-7.tcore1.HK2-Hong-Kong.as6453.net (180.87.112.189) 159.351 ms
2016/04/01 11:16:49 17 if-ge-10-0-0-1128.core1.undefined.as6453.net (180.87.160.73) 156.412 ms 156.522 ms if-ge-14-0-0-1126.core1.undefined.as6453.net (180.87.112.30) 156.605 ms
2016/04/01 11:16:49 18 * * *
2016/04/01 11:16:49 19 * * *
2016/04/01 11:16:49 20 * * *
2016/04/01 11:16:49 21 113.10.229.113 (113.10.229.113) 165.578 ms 165.818 ms 163.451 ms
2016/04/01 11:16:49 22 113.10.229.74 (113.10.229.74) 163.564 ms ae5.10g-idc.wpc.nwtgigalink.com (113.10.229.66) 162.384 ms 113.10.229.74 (113.10.229.74) 167.026 ms
2016/04/01 11:16:49 23 113.10.230.162 (113.10.230.162) 162.988 ms 162.777 ms 163.807 ms
2016/04/01 11:16:49 24 58.64.160.164 (58.64.160.164) 161.902 ms 162.396 ms 164.986 ms
2016/04/01 11:16:54 25 * * *
2016/04/01 11:16:54 26 58.64.200.76 (58.64.200.76) 162.178 ms !X 162.509 ms !X 162.356 ms !X
答案 0 :(得分:2)
我想你想把你的default:
案件的正文放到goroutine中;我怀疑它会阻止你的case <-time.After(time.Second * 2):
标签被击中。
另外,请记住,time.After
并不能保证它会在该持续时间之后完全被命中,它只表示在该持续时间之后的任何时间它将在通道上发送信号,这可能是一段时间在指定的时间后。请参阅基础time.NewTimer
我修改了您的示例:http://play.golang.org/p/TggNQ1d57Y
package main
import (
"bufio"
"fmt"
"log"
"os/exec"
"time"
)
func RunTraceroute(host string) {
errch := make(chan error, 1)
cmd := exec.Command("/usr/bin/traceroute", host)
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
go func() {
errch <- cmd.Wait()
}()
go func() {
for _, char := range "|/-\\" {
fmt.Printf("\r%s...%c", "Running traceroute", char)
time.Sleep(100 * time.Millisecond)
}
scanner := bufio.NewScanner(stdout)
fmt.Println("")
for scanner.Scan() {
line := scanner.Text()
log.Println(line)
}
}()
select {
case <-time.After(time.Second * 1):
log.Println("Timeout hit..")
return
case err := <-errch:
if err != nil {
log.Println("traceroute failed:", err)
}
}
}
func main() {
RunTraceroute("8.8.8.8")
}
哪个适合我?