golang跨平台执行Shell命令插件库cmd的使用

Golang跨平台执行Shell命令插件库cmd的使用

cmd包简介

cmd包是一个简单的包,用于在Linux、Darwin和Windows上执行shell命令。

安装

使用以下命令安装最新版本:

$ go get -u github.com/commander-cli/cmd

或者安装特定版本:

$ go get -u github.com/commander-cli/cmd@v1.0.0

基本用法

// 创建一个新命令
c := cmd.NewCommand("echo hello")

// 执行命令
err := c.Execute()
if err != nil {
    panic(err.Error())    
}

// 输出命令的标准输出和标准错误
fmt.Println(c.Stdout())
fmt.Println(c.Stderr())

配置命令

可以通过传递一个选项函数来配置命令,该函数接收命令对象作为引用传递的参数。

默认选项函数

cmd.WithCustomBaseCommand(*exec.Cmd)
cmd.WithStandardStreams
cmd.WithCustomStdout(...io.Writers)
cmd.WithCustomStderr(...io.Writers)
cmd.WithTimeout(time.Duration)
cmd.WithoutTimeout
cmd.WithWorkingDir(string)
cmd.WithEnvironmentVariables(cmd.EnvVars)
cmd.WithInheritedEnvironment(cmd.EnvVars)

示例

// 使用标准流
c := cmd.NewCommand("echo hello", cmd.WithStandardStreams)
c.Execute()

设置自定义选项

// 自定义工作目录
setWorkingDir := func (c *Command) {
    c.WorkingDir = "/tmp/test"
}

// 创建命令并执行
c := cmd.NewCommand("pwd", setWorkingDir)
c.Execute()

完整示例Demo

下面是一个完整的示例,展示如何使用cmd包执行命令并处理输出:

package main

import (
	"fmt"
	"time"
	
	"github.com/commander-cli/cmd"
)

func main() {
	// 示例1: 基本命令执行
	c1 := cmd.NewCommand("echo 'Hello, World!'")
	err := c1.Execute()
	if err != nil {
		fmt.Printf("命令执行失败: %v\n", err)
		return
	}
	fmt.Printf("输出: %s\n", c1.Stdout())

	// 示例2: 带超时的命令
	c2 := cmd.NewCommand("sleep 5", cmd.WithTimeout(2*time.Second))
	err = c2.Execute()
	if err != nil {
		fmt.Printf("命令执行失败(预期中): %v\n", err)
	}

	// 示例3: 设置工作目录
	c3 := cmd.NewCommand("pwd", func(c *cmd.Command) {
		c.WorkingDir = "/tmp"
	})
	err = c3.Execute()
	if err != nil {
		fmt.Printf("命令执行失败: %v\n", err)
		return
	}
	fmt.Printf("当前工作目录: %s\n", c3.Stdout())

	// 示例4: 捕获标准错误
	c4 := cmd.NewCommand("ls /nonexistent")
	err = c4.Execute()
	if err != nil {
		fmt.Printf("命令执行失败: %v\n", err)
		fmt.Printf("错误输出: %s\n", c4.Stderr())
	}
}

贡献指南

如果你想贡献代码,请提交pull request。对于bug修复/小的更改,一个简单的pull request就足够了。如果更改较大或希望在实现之前进行功能讨论,请随时开一个issue。

开发

请fork项目并在那里进行开发。请使用有意义的分支名称,并遵守commitlint规则。

如果要运行预提交钩子:

make init

运行测试套件:

make test

提醒: 本项目的目标是尽可能抽象特定于操作系统的命令执行。确保你的更改与Linux、Windows和OSX兼容。


更多关于golang跨平台执行Shell命令插件库cmd的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang跨平台执行Shell命令插件库cmd的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang跨平台执行Shell命令插件库cmd的使用

在Go语言中,执行Shell命令是一个常见的需求,特别是在需要与操作系统交互的场景下。Go标准库提供了os/exec包来处理命令执行,但有时我们需要更高级的功能或更简洁的API。github.com/go-cmd/cmd是一个流行的第三方库,提供了跨平台的命令执行功能,并具有一些有用的特性。

cmd库的主要特点

  1. 跨平台支持:在Windows、Linux和macOS上都能正常工作
  2. 实时输出处理:可以实时获取命令的标准输出和错误输出
  3. 状态监控:可以查询命令的执行状态
  4. 超时控制:支持设置命令执行的超时时间
  5. 简单易用:API设计简洁明了

安装cmd库

go get github.com/go-cmd/cmd

基本用法示例

简单命令执行

package main

import (
	"fmt"
	"time"
	
	"github.com/go-cmd/cmd"
)

func main() {
	// 创建一个新的Cmd,指定要执行的命令和参数
	cmdOptions := cmd.Options{
		Buffered:  false, // 非缓冲模式,实时获取输出
		Streaming: true,  // 启用流式输出
	}
	
	// 在Linux/macOS上执行ls命令
	// 在Windows上可以改为"cmd /c dir"
	command := cmd.NewCmdOptions(cmdOptions, "ls", "-l")
	
	// 启动命令
	statusChan := command.Start()
	
	// 等待命令完成并打印输出
	go func() {
		for {
			select {
			case <-statusChan:
				// 命令已完成
				return
			default:
				// 获取当前状态
				status := command.Status()
				// 打印标准输出
				for _, line := range status.Stdout {
					fmt.Println(line)
				}
				// 打印错误输出
				for _, line := range status.Stderr {
					fmt.Println("Error:", line)
				}
				time.Sleep(100 * time.Millisecond)
			}
		}
	}()
	
	// 等待命令完成
	finalStatus := <-statusChan
	fmt.Printf("命令执行完成,退出码: %d\n", finalStatus.Exit)
}

带缓冲的命令执行

package main

import (
	"fmt"
	
	"github.com/go-cmd/cmd"
)

func main() {
	// 使用缓冲模式执行命令
	cmdOptions := cmd.Options{
		Buffered:  true,  // 缓冲模式,命令完成后一次性获取输出
		Streaming: false, // 禁用流式输出
	}
	
	command := cmd.NewCmdOptions(cmdOptions, "echo", "Hello, World!")
	
	// 启动并等待命令完成
	status := <-command.Start()
	
	// 打印输出
	fmt.Println("输出:")
	for _, line := range status.Stdout {
		fmt.Println(line)
	}
	
	fmt.Printf("退出码: %d\n", status.Exit)
}

带超时的命令执行

package main

import (
	"context"
	"fmt"
	"time"
	
	"github.com/go-cmd/cmd"
)

func main() {
	// 创建一个带超时的context
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	
	command := cmd.NewCmd("sleep", "5") // 这个命令会执行5秒
	
	// 启动命令
	statusChan := command.Start()
	
	select {
	case <-ctx.Done():
		// 超时发生,停止命令
		err := command.Stop()
		if err != nil {
			fmt.Println("停止命令时出错:", err)
		} else {
			fmt.Println("命令因超时被停止")
		}
	case status := <-statusChan:
		// 命令正常完成
		fmt.Printf("命令完成,退出码: %d\n", status.Exit)
	}
}

高级用法

环境变量设置

package main

import (
	"fmt"
	
	"github.com/go-cmd/cmd"
)

func main() {
	// 创建命令并设置环境变量
	command := cmd.NewCmd("printenv", "MY_VAR")
	
	// 设置环境变量
	command.Env = append(command.Env, "MY_VAR=Hello from env")
	
	// 执行命令
	status := <-command.Start()
	
	fmt.Println("输出:")
	for _, line := range status.Stdout {
		fmt.Println(line)
	}
}

工作目录设置

package main

import (
	"fmt"
	"os"
	"path/filepath"
	
	"github.com/go-cmd/cmd"
)

func main() {
	// 获取当前工作目录
	wd, err := os.Getwd()
	if err != nil {
		fmt.Println("获取工作目录失败:", err)
		return
	}
	
	// 创建命令并设置工作目录
	command := cmd.NewCmd("pwd")
	command.Dir = filepath.Join(wd, "..") // 设置为上级目录
	
	// 执行命令
	status := <-command.Start()
	
	fmt.Println("当前工作目录:")
	for _, line := range status.Stdout {
		fmt.Println(line)
	}
}

注意事项

  1. 在Windows上执行命令时,可能需要使用cmd /c作为前缀
  2. 对于长时间运行的命令,建议使用流式输出模式以避免内存问题
  3. 命令执行可能会因为权限问题而失败,需要适当处理错误
  4. 在并发环境下使用时,需要注意命令状态的同步访问

github.com/go-cmd/cmd库提供了比标准库os/exec更简洁的API和更多有用的功能,特别适合需要实时处理命令输出或需要更精细控制命令执行的场景。

回到顶部