通过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 }
本文来自博客园,作者:xiaoyongdata(微信号:xiaoyongdata),转载请注明原文链接:https://www.cnblogs.com/xiaoyongdata/p/15529717.html