通过go调用bat解决乱码核心代码

背景:通过go写的程序调用dos命令(如dir c:),返回值往往有中文,默认会出现乱码。

解决:转码。

代码:GO

package shellLib

import (
    "golang.org/x/text/encoding/simplifiedchinese"
)

type Charset string

const (
    UTF8    = Charset("UTF-8")
    GB18030 = Charset("GB18030")
)

//解决执行bat文件时返回的内容是乱码
func ConvertByte2String(byte []byte, charset Charset) string {
    var str string
    switch charset {
    case GB18030:
        decodeBytes, _ := simplifiedchinese.GB18030.NewDecoder().Bytes(byte)
        str = string(decodeBytes)
    case UTF8:
        fallthrough
    default:
        str = string(byte)
    }

    return str
}

 

调用代码:

func ExecuteByFile(title string,exitChan chan string,cmdInput,shFileName,osName string) (cmdResult string) {
    defer func() {
        if p := recover(); p != nil {
            fmt.Printf("出错了: %v", p)
            debug.PrintStack()
        }
//统一在退出前关闭心跳 setChan(title,exitChan,cmdResult) }()
if strings.TrimSpace(cmdInput)==""{ log.Println("脚本为空,程序中止") return "#ERROR#:脚本为空,程序中止。" } //time.Sleep(3*time.Second)//模拟长时间执行 //重要思路:不要执行命令,而是将命令+参数写到脚本文件(bat,sh)中,然后简单执行文件即可。 ScriptToShell(shFileName,osName,cmdInput) //转为执行shell脚本 cmdInput = shFileName var sb bytes.Buffer if osName=="windows"{ cmd := exec.Command("cmd.exe", "/C", shFileName) cmd.Stdout = &sb err := cmd.Run() if err != nil { cmdResult = fmt.Sprintf("#ERROR#%s(请在dos下直接运行【%s】来查错)",err.Error(),shFileName) log.Printf("#ERROR#%s",cmdResult) return } cmdResult = ConvertByte2String(sb.Bytes(), GB18030) return } //在linux平台下执行脚本文件 command := "/bin/bash" params := []string{"-c", cmdInput} var contentArray = make([]string, 0, 5) contentArray = contentArray[0:0] cmd := exec.Command(command, params...) //获取标准输出:要点1 sbStdErr := bytes.NewBuffer(nil) cmd.Stderr = sbStdErr //实时获取:要点1:需要使用 Cmd 结构的 StdoutPipe() 方法创建一个管道连接到命令执行的输出 stdout, err := cmd.StdoutPipe() if err != nil { fmt.Fprintln(os.Stderr, "error=>", err.Error()) return err.Error() } var index int cmd.Start() // Start开始执行c包含的命令,但并不会等待该命令完成即返回。Wait方法会返回命令的返回状态码并在命令返回后释放相关的资源。 readerStdOut := bufio.NewReader(stdout) //要点2:然后用 for 循环从管道中实时读取命令执行的输出并打印到终端 //实时循环读取输出流中的一行内容 for { line, err2 := readerStdOut.ReadString('\n') if err2 != nil || io.EOF == err2 { //log.Printf("error:%v\n",err2.Error()) //获取标准输出:要点2 errMsg := string(sbStdErr.Bytes()) errMsg = strings.TrimSpace(errMsg) if errMsg!=""{ sb.WriteString(errMsg) fmt.Printf("#error:%s\n", errMsg) } break }else{ sb.WriteString(line+"\n") } fmt.Printf("日志:【%s】\n",strings.TrimSpace(line)) index++ contentArray = append(contentArray, line) } //重要说明:不要用Wait,找了好久啊。。。 //cmd.Wait() //往通道中存入一个值以结束心跳 cmdResult = sb.String() cmdResult = strings.TrimSpace(cmdResult) //不能在defer中设置,defer编译时cmdResult还是空的,只是在return前执行 //setChan(title,exitChan,cmdResult) return }

 主方法:

func ExecuteCmd(loginId,mapType,tcpUrl,title,cmdStr,scriptFile string,heartSec int)(result string)  {
    log.Println("ExecuteCmd.tcpURL:%s\n",tcpUrl)
    sysMap[loginId] = mapType
    //执行前清空已有的日志缓存
    //sbLog.Reset()
    //默认每5秒提供一次心跳
    exitChan := make(chan string)
    //在内部判断_双引号替换符存在且不为空时,会将指定的符号替换为双引号。执行完以后会清空“_双引号替换符”的值。
    cmdStr = strings.ReplaceAll(cmdStr,"`",`"`)
    //获取文件名
    osName := osMap[loginId]
    //如果为空,则根据loginId自己拼接,不为空则使用指定路径
    if scriptFile==""{
        scriptFile = fmt.Sprintf("%s/%s",fileLib.CurrDir(),loginId)
        if strings.Contains(osName,"win"){
            scriptFile = fmt.Sprintf("%s.bat",scriptFile)
        }else{
            scriptFile = fmt.Sprintf("%s.sh",scriptFile)
        }
    }
    go PrintHeart(loginId,mapType,tcpUrl,title,exitChan, MainParam.LogPushFile,heartSec)
    result = shellLib.ExecuteByFile(title,exitChan,cmdStr,scriptFile,osName)
    //下面的函数是等待信号的程序,会一直阻塞,直到解除(所以这个方法不要用go)
    return result
}

 

posted @ 2021-11-09 16:42  xiaoyongdata  阅读(661)  评论(0编辑  收藏  举报