• gocommand:一个跨平台的golang命令行执行package


        最近在做一个项目的时候,需要使用golang来调用操作系统中的命令行,来执行shell命令或者直接调用第三方程序,这其中自然就用到了golang自带的exec.Command.

        但是如果直接使用原生exec.Command会造成大量的重复代码,网上搜了一圈又没有找到对exec.Command相应的封装包,索性自己封装了一个,取名为gocommand.目前支持Linux和Windows,欢迎各位大神在github上提交代码补充其他平台的实现.

        下面介绍一下gocommand库的实现思路:

    package gocommand
    
    // 命令行接口
    type Commander interface {
    	// 执行命令行并返回结果
    	// args: 命令行参数
    	// return: 进程的pid, 命令行结果, 错误消息
    	Exec(args ...string) (int, string, error)
    
    	// 异步执行命令行并通过channel返回结果
    	// stdout: chan结果
    	// args: 命令行参数
    	// return: 进程的pid
    	// exception: 协程内的命令行发生错误时,会panic异常
    	ExecAsync(stdout chan string, args ...string) int
    
    	// 执行命令行(忽略返回值)
    	// args: 命令行参数
    	// return: 错误消息
    	ExecIgnoreResult(args ...string) error
    }

        gocommand目前的命令行执行函数都是源于Commander接口,目前该接口定义了3个函数,分别是:执行命令行病返回结果;异步执行命令行并得到结果;执行命令行并忽略结果.

    package gocommand
    
    import (
    	"runtime"
    )
    
    // Command的初始化函数
    func NewCommand() Commander {
    	var cmd Commander
    
    	switch runtime.GOOS {
    	case "linux":
    		cmd = NewLinuxCommand()
    	case "windows":
    		cmd = NewWindowsCommand()
    	default:
    		cmd = NewLinuxCommand()
    	}
    
    	return cmd
    }

        创建一个Command的实现,并根据当前的操作系统,返回对应的实现函数,目前只实现了Linux和Windows,(Mac留给各位大神(土豪)了),其中LinuxCommand的代码实现如下:

    package gocommand
    
    import (
    	"io/ioutil"
    	"os"
    	"os/exec"
    	"syscall"
    )
    
    // LinuxCommand结构体
    type LinuxCommand struct {
    }
    
    // LinuxCommand的初始化函数
    func NewLinuxCommand() *LinuxCommand {
    	return &LinuxCommand{}
    }
    
    // 执行命令行并返回结果
    // args: 命令行参数
    // return: 进程的pid, 命令行结果, 错误消息
    func (lc *LinuxCommand) Exec(args ...string) (int, string, error) {
    	args = append([]string{"-c"}, args...)
    	cmd := exec.Command(os.Getenv("SHELL"), args...)
    
    	cmd.SysProcAttr = &syscall.SysProcAttr{}
    
    	outpip, err := cmd.StdoutPipe()
            defer outpip.Close()
    	if err != nil {
    		return 0, "", err
    	}
    
    	err = cmd.Start()
    	if err != nil {
    		return 0, "", err
    	}
    
    	out, err := ioutil.ReadAll(outpip)
    	if err != nil {
    		return 0, "", err
    	}
    
    	return cmd.Process.Pid, string(out), nil
    }
    
    // 异步执行命令行并通过channel返回结果
    // stdout: chan结果
    // args: 命令行参数
    // return: 进程的pid
    // exception: 协程内的命令行发生错误时,会panic异常
    func (lc *LinuxCommand) ExecAsync(stdout chan string, args ...string) int {
    	var pidChan = make(chan int, 1)
    
    	go func() {
    		args = append([]string{"-c"}, args...)
    		cmd := exec.Command(os.Getenv("SHELL"), args...)
    
    		cmd.SysProcAttr = &syscall.SysProcAttr{}
    
    		outpip, err := cmd.StdoutPipe()
                    defer outpip.Close()
    		if err != nil {
    			panic(err)
    		}
    
    		err = cmd.Start()
    		if err != nil {
    			panic(err)
    		}
    
    		pidChan <- cmd.Process.Pid
    
    		out, err := ioutil.ReadAll(outpip)
    		if err != nil {
    			panic(err)
    		}
    
    		stdout <- string(out)
    	}()
    
    	return <-pidChan
    }
    
    // 执行命令行(忽略返回值)
    // args: 命令行参数
    // return: 错误消息
    func (lc *LinuxCommand) ExecIgnoreResult(args ...string) error {
    	args = append([]string{"-c"}, args...)
    	cmd := exec.Command(os.Getenv("SHELL"), args...)
    
    	cmd.Stdout = os.Stdout
    	cmd.Stderr = os.Stderr
    	cmd.SysProcAttr = &syscall.SysProcAttr{}
    
    	err := cmd.Run()
    
    	return err
    }

        Exec函数会在执行命令行后阻塞,直到得到命令的执行结果;ExecAsync函数在内部使用了协程来执行命令行,并通过参数中的chan变量把结果传递出去;ExecNoWait会无阻赛地执行命令行.Windows平台上的实现类似,只是Shell命令换成了cmd.

        使用示例如下:

    package main
    
    import (
    	"log"
    
    	"github.com/lizongshen/gocommand"
    )
    
    func main() {
    	_, out, err := gocommand.NewCommand().Exec("ls /")
    	if err != nil {
    		log.Panic(err)
    	}
    
    	log.Println(out)
    
    }

        代码的单元测试情况:

    [lizongshen@localhost gocommand]$ go test
    bin   dev  home  lib64	mnt  proc  run	 srv  tmp  var
    boot  etc  lib	 media	opt  root  sbin  sys  usr
    PASS
    ok  	gocommand	0.007s

        github开源地址:https://github.com/lizongshen/gocommand.

    作者:DSeven
    出处:http://www.cnblogs.com/lizongshen/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

  • 相关阅读:
    回溯 八皇后问题 与 0-1背包
    技术学习
    线程间通信
    计算机网络基础知识总结(各种协议)
    大数据Phoenix专题
    java中HashMap详解
    使用LocalBroadcastManager解决BroadcastReceiver安全问题
    Paint类常用方法
    链表结构对象池的一种实现
    android内存及内存溢出分析
  • 原文地址:https://www.cnblogs.com/lizongshen/p/9375158.html
Copyright © 2020-2023  润新知