代码拉取完成,页面将自动刷新
package gcs
import (
"context"
"fmt"
"os/exec"
"strings"
"time"
"gitee.com/liumou_site/logger"
"gitee.com/liumou_site/gbm"
"github.com/spf13/cast"
)
// RunShell 执行Shell命令。
//
// 该方法接受一个或多个字符串参数作为命令,将其存储在api.args中,
// 然后调用api.shellSystem()方法来执行命令。
// 此方法不返回任何值。
func (api *ApiShell) RunShell(command ...string) {
// 将传入的命令参数存储到api实例的args字段中。
api.args = command
// 调用shellSystem方法执行存储在args中的命令。
api.shellSystem()
}
// RunShellList 批量执行命令
//
// @Description: 通过传入完整的命令切片遍历执行,当遇到执行错误立即返回
// @receiver api
// @param cs 需要执行的命令切片,每个切片元素必须是完整命令
func (api *ApiShell) RunShellList(cs []string) {
for i, c := range cs {
api.RunShell(c)
if api.Err != nil {
logs.Error("第[ %d ]条命令执行失败", i)
fmt.Println(c)
return
}
}
}
// RunScript 通过生成脚本的方式执行Shell,支持Shell管道
//
// @Description:
// @receiver api
// @param command 需要执行的命令,例如 'apt', 'update',命令与选项可以分开传入
func (api *ApiShell) RunScript(command ...string) {
api.ScriptMode = true
api.args = command
api.Text = gbm.SliceToString(command, " ")
err := createScript(api.Text, api.Script, false)
if err == nil {
api.args = []string{api.Script}
api.shellSystem()
} else {
if api.PrintErr {
logs.Error("文件创建失败: ", api.Script)
}
}
api.ScriptMode = false
}
// RunTerminal 通过调用图形化终端程序的方式执行Shell命令,使用脚本封装的方式,支持Shell管道
//
// @Description:
// @receiver api
// @param command 需要执行的命令,例如 'apt', 'update',命令与选项可以分开传入
func (api *ApiShell) RunTerminal(command ...string) {
if !api.TerminalBool {
api.Err = fmt.Errorf("当前系统暂不支持终端执行命令")
return
}
api.ScriptMode = true
api.Text = api.Terminal + " " + api.TerminalArg + " " + gbm.SliceToString(command, " ")
if api.Debug {
logs.Debug(api.Text)
}
api.args = command
if api.Debug {
fmt.Println(api.args)
}
err := createScript(api.Text, api.Script, false)
if err == nil {
api.args = []string{api.Script}
api.shellSystem()
} else {
if api.PrintErr {
logs.Error("文件创建失败: ", api.Script)
}
}
api.ScriptMode = false
}
// shellInit
//
// @Description: 初始化执行参数
// @receiver api
func (api *ApiShell) shellInit() {
var argTmp string
api.Strings = "" // 初始化输出
api.Result = false // 初始化执行结果
api.Err = nil // 初始化错误
if api.Debug {
logs.Debug("处理前参数: %d", len(api.args))
fmt.Println(api.args)
}
api.args = gbm.SliceToSlice(api.args, " ") // 去除空元素
if api.Debug {
logs.Debug("处理后参数: %d", len(api.args))
fmt.Println(api.args)
}
api.args = gbm.SliceRemoveNull(api.args)
if len(api.args) == 1 { // 判断命令参数数量
api.args = strings.Split(api.args[0], " ")
}
api.Text = gbm.SliceToString(api.args, " ")
api.cmdName = "/bin/bash" // 定义命令路径
if CheckCmd(api.args[0]) { // 如果命令在PATH中则使用命令执行并从参数中移除命令
api.cmdName = api.args[0] // 使用第一个参数作为命令
api.args, api.Err = gbm.SliceRemoveIndex(api.args, 0) // 移除第一个元素
if api.Err != nil {
return
}
argTmp = ""
api.argRun = api.args // 在切片头部添加/C参数
} else {
if api.OsType == "windows" {
api.cmdName = "cmd"
argTmp = "/C"
} else {
argTmp = "-c"
}
api.argRun = append([]string{argTmp}, api.args...) // 在切片头部添加-c参数
}
}
// shellSystem 执行命令并将结果赋值到结构体
//
// @Description:
// @receiver api
func (api *ApiShell) shellSystem() {
var cmd *exec.Cmd
api.shellInit()
if len(api.args) > 0 {
cmd = exec.Command(api.cmdName, api.argRun...) // 创建命令实例
} else {
cmd = exec.Command(api.cmdName) // 创建命令实例
}
if api.Err != nil {
return
}
if api.ScriptMode {
if api.Debug {
logs.Debug(api.Script)
}
if api.TerminalBool {
cmd = exec.Command(api.Terminal, api.TerminalArg, api.Script)
} else {
cmd = exec.Command("/bin/bash", "-c", api.Script)
}
}
// 命令的错误输出和标准输出都连接到同一个管道
stdout, err := cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout
if api.Ignore {
// 如果开启了屏蔽标准输出,则设置nil
cmd.Stdout = nil
}
if api.BlackHole {
// 如果开启了黑洞屏蔽错误输出,则设置nil
cmd.Stderr = nil
}
api.Err = err
if err != nil {
if api.PrintErr {
logs.Error("管道创建失败")
}
if api.Debug {
logs.Debug("Execute command: ", api.Text)
}
api.ExitCode = 1
return
}
api.Err = cmd.Start()
if api.Err != nil {
logs.Error("命令启动失败 :", api.Err)
logs.Debug("Execute command: ", api.Text)
api.ExitCode = 2
return
}
// 从管道中实时获取输出并打印到终端
for {
tmp := make([]byte, 1024)
_, err := stdout.Read(tmp)
// 如果开启了实时打印,则将信息逐行输出到终端
if api.Realtime {
fmt.Print(string(tmp))
}
api.Strings = api.Strings + cast.ToString(string(tmp))
if err != nil {
break
}
}
// 等待命令退出,并等待任何复制到stdin或从stdout或stderr复制完成。
api.Err = cmd.Wait()
// ExitCode返回已退出进程的退出代码,如果进程尚未退出或被信号终止,则返回-1。
api.ExitCode = cmd.ProcessState.ExitCode()
if api.PrintInfo {
logs.Info("Exit Code: ", cmd.ProcessState.ExitCode())
}
if api.Err == nil {
if api.ExitCode != 0 {
if api.PrintErr {
logs.Error("Error :", api.Err)
}
if api.Debug {
logs.Debug("Execute command: ", api.Text)
}
}
if api.ExitCode == 0 {
api.Result = true
api.Err = nil
}
}
}
// argsHandle 参数处理
//
// @Description:
// @receiver api
func (api *ApiShell) argsHandle() {
api.Strings = "" // 初始化输出
api.Result = false // 初始化执行结果
api.Err = nil // 初始化错误
api.Result = false // 重置执行结果
if api.Debug {
logs.Debug("处理前参数: %d", len(api.args))
}
api.args = gbm.SliceToSlice(api.args, " ") // 去除空元素
if api.Debug {
logs.Debug("处理后参数: %d", len(api.args))
}
api.args = append([]string{"-c"}, api.args...) // 在切片头部添加-S参数
}
// RunTimeout 执行系统命令并设置超时时间
//
// @Description:
// @receiver api
// @param n 超时时间(秒)
// @param command 需要执行的命令,例如 'apt', 'update',命令与选项可以分开传入
// @return *ApiShell
func (api *ApiShell) RunTimeout(n time.Duration, command ...string) *ApiShell {
api.args = command
api.shellInit() // 处理参数
if api.Err != nil {
return api
}
ctx, cancel := context.WithTimeout(context.Background(), n*time.Second) // 创建带有超时时间的上下文对象
defer cancel()
if api.Debug {
logs.Debug("执行命令: %s", api.cmdName)
logs.Debug("执行参数: %s", api.argRun)
}
cmd := exec.CommandContext(ctx, api.cmdName, api.argRun...) // 创建命令对象,并将上下文对象传递给 CommandContext 方法
// 执行命令,并等待命令执行完成
if api.Err = cmd.Run(); api.Err != nil {
// 如果是超时错误,则返回超时信息
if ctx.Err() == context.DeadlineExceeded {
if api.PrintErr {
logger.Error("命令执行超时: ", api.Err.Error())
}
}
}
return api
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。