我想运行一个命令并打印其 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
最佳答案
我想你想把你的 body default:
将 case 转换为 goroutine;我怀疑它阻止了你的 case <-time.After(time.Second * 2):
标签被击中。
另外,请记住 time.After
不保证它会在该持续时间之后准确命中,它只是说在该持续时间之后的任何时间它将在 channel 上发送信号,这可能是在指定持续时间之后的一段时间。请参阅基础 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")
}
哪个对我有用
关于go - 使用超时运行命令并在 go 中一次读取一行标准输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61767109/