github.com/qxnw/lib4go@v0.0.0-20180426074627-c80c7e84b925/sysinfo/pipes/pipes.go (about) 1 package pipes 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "os" 8 "os/exec" 9 "strings" 10 "time" 11 ) 12 13 // RunString Convert a shell command with a series of pipes into 14 // correspondingly piped list of *exec.Cmd 15 // If an arg has spaces, this will fail 16 func RunString(s string) (string, error) { 17 buf := bytes.NewBuffer([]byte{}) 18 sp := strings.Split(s, "|") 19 cmds := make([]*exec.Cmd, len(sp)) 20 // create the commands 21 for i, c := range sp { 22 cs := strings.Split(strings.TrimSpace(c), " ") 23 cmd := cmdFromStrings(cs) 24 cmds[i] = cmd 25 } 26 27 cmds = AssemblePipes(cmds, nil, buf) 28 if err := RunCmds(cmds); err != nil { 29 return "", err 30 } 31 32 b := buf.Bytes() 33 return string(b), nil 34 } 35 36 func cmdFromStrings(cs []string) *exec.Cmd { 37 if len(cs) == 1 { 38 return exec.Command(cs[0]) 39 } else if len(cs) == 2 { 40 return exec.Command(cs[0], cs[1]) 41 } 42 return exec.Command(cs[0], cs[1:]...) 43 } 44 45 //RunStrings Convert sequence of tokens into commands, 46 // using "|" as a delimiter 47 func RunStrings(tokens ...string) (string, error) { 48 if len(tokens) == 0 { 49 return "", nil 50 } 51 buf := bytes.NewBuffer([]byte{}) 52 cmds := []*exec.Cmd{} 53 args := []string{} 54 // accumulate tokens until a | 55 for _, t := range tokens { 56 if t != "|" { 57 args = append(args, t) 58 } else { 59 cmds = append(cmds, cmdFromStrings(args)) 60 args = []string{} 61 } 62 } 63 cmds = append(cmds, cmdFromStrings(args)) 64 cmds = AssemblePipes(cmds, nil, buf) 65 if err := RunCmds(cmds); err != nil { 66 return "", fmt.Errorf("%s; %s", err.Error(), string(buf.Bytes())) 67 } 68 69 b := buf.Bytes() 70 return string(b), nil 71 } 72 73 //AssemblePipes Pipe stdout of each command into stdin of next 74 func AssemblePipes(cmds []*exec.Cmd, stdin io.Reader, stdout io.Writer) []*exec.Cmd { 75 cmds[0].Stdin = stdin 76 cmds[0].Stderr = stdout 77 // assemble pipes 78 for i, c := range cmds { 79 if i < len(cmds)-1 { 80 cmds[i+1].Stdin, _ = c.StdoutPipe() 81 cmds[i+1].Stderr = stdout 82 } else { 83 c.Stdout = stdout 84 c.Stderr = stdout 85 } 86 } 87 return cmds 88 } 89 90 // RunCmds run series of piped commands 91 func RunCmds(cmds []*exec.Cmd) error { 92 // start processes in descending order 93 for i := len(cmds) - 1; i > 0; i-- { 94 if err := cmds[i].Start(); err != nil { 95 return err 96 } 97 } 98 // run the first process 99 if err := cmds[0].Run(); err != nil { 100 return err 101 } 102 // wait on processes in ascending order 103 for i := 1; i < len(cmds); i++ { 104 if err := cmds[i].Wait(); err != nil { 105 return err 106 } 107 } 108 return nil 109 } 110 111 //BashRun 通过bash 执行命令 112 func BashRun(cmd string) (content string, err error) { 113 cmd1 := exec.Command("/bin/bash", "-c", cmd) 114 var out bytes.Buffer 115 cmd1.Stdout = &out 116 cmd1.Stderr = &out 117 err = cmd1.Start() 118 if err != nil { 119 return 120 } 121 err = cmd1.Wait() 122 if err != nil { 123 return 124 } 125 126 content = strings.Trim(out.String(), "\n") 127 return 128 } 129 130 //Run 通过管道方式执行命令 131 func Run(cmds []*exec.Cmd) (content string, err error) { 132 var out bytes.Buffer 133 AssemblePipes(cmds, os.Stdin, &out) 134 err = RunCmds(cmds) 135 time.Sleep(time.Second) 136 if err != nil { 137 err = fmt.Errorf("命令执行失败:%s,err:%v", strings.Trim(out.String(), "\n"), err) 138 return 139 } 140 content = strings.Trim(out.String(), "\n") 141 return 142 }