golang实现Unix Shell风格命令链式执行的插件库command-chain的使用
golang实现Unix Shell风格命令链式执行的插件库command-chain的使用
go-command-chain是一个用于轻松配置和运行命令链的Go库,类似于Unix shell中的管道操作。
基础示例
链式命令执行
以下是一个模拟Unix Shell管道操作的示例,统计日志文件中包含"error"的行数:
package main
import (
"fmt"
"github.com/rainu/go-command-chain"
)
func main() {
stdOut, stdErr, err := cmdchain.Builder().
Join("cat", "log_file.txt"). // 第一个命令:读取文件
Join("grep", "error"). // 第二个命令:过滤包含error的行
Join("wc", "-l"). // 第三个命令:统计行数
Finalize().RunAndGet() // 执行并获取结果
if err != nil {
panic(err)
}
if stdErr != "" {
panic(stdErr)
}
fmt.Printf("Errors found: %s", stdOut)
}
直接执行Shell命令字符串
你也可以直接执行完整的Shell命令字符串:
package main
import (
"fmt"
"github.com/rainu/go-command-chain"
)
func main() {
stdOut, stdErr, err := cmdchain.Builder().
JoinShellCmd(`cat log_file.txt | grep error | wc -l`). // 直接执行Shell管道命令
Finalize().RunAndGet()
if err != nil {
panic(err)
}
if stdErr != "" {
panic(stdErr)
}
fmt.Printf("Errors found: %s", stdOut)
}
高级功能
输入注入
可以为每个命令注入多个不同的输入流:
package main
import (
"github.com/rainu/go-command-chain"
"strings"
)
func main() {
inputContent1 := strings.NewReader("content from application itself\n")
inputContent2 := strings.NewReader("another content from application itself\n")
err := cmdchain.Builder().
Join("echo", "test").WithInjections(inputContent1, inputContent2). // 注入两个输入流
Join("grep", "test").
Join("wc", "-l").
Finalize().Run()
if err != nil {
panic(err)
}
}
标准输出和错误输出的分流
可以为每个命令的标准输出和错误输出指定不同的写入目标:
package main
import (
"bytes"
"github.com/rainu/go-command-chain"
)
func main() {
echoErr := &bytes.Buffer{} // 存储echo命令的错误输出
echoOut := &bytes.Buffer{} // 存储echo命令的标准输出
grepErr := &bytes.Buffer{} // 存储grep命令的错误输出
err := cmdchain.Builder().
Join("echo", "test").WithOutputForks(echoOut).WithErrorForks(echoErr). // 分流echo的输出
Join("grep", "test").WithErrorForks(grepErr). // 分流grep的错误输出
Join("wc", "-l").
Finalize().Run()
if err != nil {
panic(err)
}
}
为什么使用这个库?
相比直接调用shell执行管道命令,这个库有以下优势:
- 不依赖于系统shell及其特定版本
- 可以精确控制每个单独的命令
- 避免了复杂的管道语法问题
- 提供了更灵活的输入输出控制能力
相比之下,直接调用shell的方式:
package main
import (
"os/exec"
)
func main() {
exec.Command("sh", "-c", "cat log_file.txt | grep error | wc -l").Run()
}
存在以下问题:
- 必须安装特定版本的shell
- 只能控制父进程(shell命令本身)
- 管道语法可能因shell版本而异
更多关于golang实现Unix Shell风格命令链式执行的插件库command-chain的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现Unix Shell风格命令链式执行的插件库command-chain的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang实现Unix Shell风格命令链式执行 - command-chain库
command-chain是一个用于Golang的轻量级库,它允许你以类似Unix Shell管道的方式链式执行多个命令。下面我将介绍如何使用这个库。
安装
go get github.com/rainu/go-command-chain
基本用法
简单命令链
package main
import (
"fmt"
"os"
"github.com/rainu/go-command-chain/pkg"
)
func main() {
// 创建命令链
chain := commandchain.Builder().
Join("echo", "hello world"). // 第一个命令
Join("grep", "hello"). // 第二个命令
Join("wc", "-l"). // 第三个命令
Finalize()
// 执行命令链
err := chain.Run()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}
带错误处理和输出捕获
package main
import (
"fmt"
"os"
"github.com/rainu/go-command-chain/pkg"
)
func main() {
var output string
// 创建命令链并捕获输出
chain := commandchain.Builder().
Join("ls", "-la"). // 列出目录内容
Join("grep", "go.mod"). // 过滤包含go.mod的行
Capture(&output). // 捕获最终输出
Finalize()
// 执行命令链
err := chain.Run()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Printf("Found go.mod: %s\n", output)
}
设置工作目录和环境变量
package main
import (
"fmt"
"os"
"github.com/rainu/go-command-chain/pkg"
)
func main() {
var output string
// 创建命令链并设置工作目录和环境变量
chain := commandchain.Builder().
WorkingDir("/tmp"). // 设置工作目录
Env("MY_VAR", "some_value"). // 设置环境变量
Join("env"). // 打印环境变量
Join("grep", "MY_VAR"). // 过滤MY_VAR
Capture(&output). // 捕获输出
Finalize()
err := chain.Run()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Printf("Environment variable: %s\n", output)
}
错误处理和调试
package main
import (
"fmt"
"os"
"github.com/rainu/go-command-chain/pkg"
)
func main() {
// 创建命令链并启用调试
chain := commandchain.Builder().
Debug(true). // 启用调试输出
Join("ls", "nonexistent_dir"). // 这个命令会失败
Join("wc", "-l"). // 这个命令不会执行
Finalize()
err := chain.Run()
if err != nil {
// 检查是否是退出错误
if exitErr, ok := err.(*exec.ExitError); ok {
fmt.Printf("Command failed with exit code %d\n", exitErr.ExitCode())
} else {
fmt.Printf("Error: %v\n", err)
}
os.Exit(1)
}
}
高级特性
自定义命令执行器
package main
import (
"fmt"
"os"
"os/exec"
"github.com/rainu/go-command-chain/pkg"
)
func main() {
// 自定义执行器函数
executor := func(cmd *exec.Cmd) error {
fmt.Printf("Executing: %v\n", cmd.Args)
return cmd.Run()
}
chain := commandchain.Builder().
WithExecutor(executor). // 使用自定义执行器
Join("echo", "custom exec").
Finalize()
err := chain.Run()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}
条件执行
package main
import (
"fmt"
"os"
"github.com/rainu/go-command-chain/pkg"
)
func main() {
shouldRun := true
chain := commandchain.Builder().
Join("echo", "always runs").
JoinIf(shouldRun, "echo", "conditional command").
Finalize()
err := chain.Run()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}
最佳实践
- 错误处理:始终检查Run()方法的返回值
- 资源清理:长时间运行的命令链应设置适当的超时
- 安全性:避免将用户输入直接传递给命令,防止命令注入
- 调试:在开发时启用Debug(true)以查看执行的命令
command-chain库提供了一种简洁的方式来构建和执行命令链,特别适合需要将多个命令行工具串联使用的场景。它的API设计模仿了Unix Shell的管道操作,使得代码更易于理解和维护。