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  }