1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
package main
import (
"bytes"
"fmt"
"log"
"os/exec"
"strings"
"time"
"syscall"
)
// 删除输出的\x00和多余的空格
func trimOutput(buffer bytes.Buffer) string {
return strings.TrimSpace(string(bytes.TrimRight(buffer.Bytes(), "\x00")))
}
// 实时打印输出
func traceOutput(out *bytes.Buffer) {
offset := 0
t := time.NewTicker(time.Second)
defer t.Stop()
for {
<-t.C
result := bytes.TrimRight((*out).Bytes(), "\x00")
size := len(result)
rows := bytes.Split(bytes.TrimSpace(result), []byte{'\n'})
nRows := len(rows)
newRows := rows[offset:nRows]
if result[size-1] != '\n' {
newRows = rows[offset : nRows-1]
}
if len(newRows) < offset {
continue
}
for _, row := range newRows {
log.Println(string(row))
}
offset += len(newRows)
}
}
// 运行Shell命令,设定超时时间(秒)
func ShellCmdTimeout(timeout int, cmd string, args ...string) (stdout, stderr string, e error) {
if len(cmd) == 0 {
e = fmt.Errorf("cannot run a empty command")
return
}
var out, err bytes.Buffer
command := exec.Command(cmd, args...)
command.Stdout = &out
command.Stderr = &err
command.Start()
// 启动routine等待结束
done := make(chan error)
go func() { done <- command.Wait() }()
// 启动routine持续打印输出
go traceOutput(&out)
// 设定超时时间,并select它
after := time.After(time.Duration(timeout) * time.Second)
select {
case <-after:
command.Process.Signal(syscall.SIGINT)
time.Sleep(time.Second)
command.Process.Kill()
log.Printf("运行命令(%s)超时,超时设定:%v 秒。",
fmt.Sprintf(`%s %s`, cmd, strings.Join(args, " ")), timeout)
case <-done:
}
stdout = trimOutput(out)
stderr = trimOutput(err)
return
}
func main() {
stdout, stderr, e := ShellCmdTimeout(5, "ping", "114.114.114.114")
log.Println("stdout:", stdout)
log.Println("stderr:", stderr)
log.Println(e)
}
|