分享
  1. 首页
  2. 文章

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

lizongshen · · 1513 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

最近在做一个项目的时候,需要使用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: 错误消息
	ExecNoWait(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()
	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()
		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) ExecNoWait(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.


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:lizongshen

查看原文:gocommand:一个跨平台的golang命令行执行package

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1513 次点击
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏