登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> CLQ工作室开源代码 - [函数库] >> 主题: [golang]取所有命令行返回     [回主站]     [分站链接]
标题
[golang]取所有命令行返回
clq
浏览(169) + 2023-05-25 14:39:16 发表 编辑

关键字:

[golang]取所有命令行返回

golang 目前的实现是错误的,至少在 windows 下是如此。以下也是参考网友的解决方案,只在 windows 上实测通过。
关键字是
wg.Add(3)
可以在源码库的第三方库中搜索到很多相关的内容

----------------------------------------------------------------

//执行一个命令,并一直读取输出,包括标准输出和标准错误
//arg ...string 的参数类型只能放到参数列表中的最后
func Execute_ShellCmd(s_cmd string, exe_path, work_path string, on_out func(string), arg ...string) (string) {

defer PrintError("Execute_ShellCmd()"); //其实可以不用

//var r = make([]interface{}, 0, 1);
//var r = make([]interface{}, 0, 1);


//cmd := exec.Command(s_cmd);
// cmd := exec.Command(GetCurrentPath() + "/map_exe2/" + "ConsoleContour.exe",

// // "-image_width=1920",
// // "-image_height=1080",
// "-image_width=" + image_width,
// "-image_height=" + image_height,
// "-method=mba",
// "");

////fn := GetCurrentPath() + "/tmp1.bat";

////SaveToFile(s_cmd, fn);

////cmd := exec.Command(GetCurrentPath() + "/tmp1.bat");
//cmd := exec.Command(s_cmd, arg...);
cmd := exec.Command(exe_path + "/" + s_cmd, arg...); //目前必须是这样,在目前的 golang 实现中最后第一个参数会转化成 cmd.Path ,所以在后面再指定 cmd.Path 是没有意义的
//cmd := exec.Command("gcc"); //
//cmd := exec.Command("gcc", "--version"); //

//https://blog.csdn.net/yoorxee/article/details/123323716
//https://www.5axxw.com/questions/content/9w2m34
////var wg sync.WaitGroup
////wg.Add(3)

//--------
//工作目录
cmd.Dir = work_path;

//----------------------------------------------------------------
stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()

stdin, _ := cmd.StdinPipe()

cmd.Start()

// 读
var wg sync.WaitGroup; //应该是等待一组 “线程” 结束
wg.Add(3); //应该是指要等待后面的几个 “线程”

//这是指的第 1 个线程 //stderr
go func() {
defer wg.Done()
for {
buf := make([]byte, 1024)
n, err := stderr.Read(buf)

if n > 0 {
fmt.Println("stderr:"); //实测可以看到 ffmpeg 的交互信息居然都是从这里取得的
fmt.Println(string(buf[:n]));

if (on_out != nil) { on_out(string(buf[:n])); }

}

if n == 0 {
break
}

if err != nil {
log.Printf("read err %v", err)
return
}
}
}();

//这是指的第 2 个线程 //stdout
go func() {
defer wg.Done()
for {
buf := make([]byte, 1024)
n, err := stdout.Read(buf)

if n == 0 {
break
}

if n > 0 {
fmt.Println("stdout:");
fmt.Println(string(buf[:n]));

if (on_out != nil) { on_out(string(buf[:n])); }

}

if n == 0 {
break
}

if err != nil {
log.Printf("read out %v", err)
return
}

}
}()

//这是指的第 2 个线程 //stdin //这里应该没有等待,直接输入就退出了
// 写
go func() {

stdin.Write([]byte("y\n\n")); //对于 ffmpeg 输入 "y" 就可以了,表示确认覆盖文件
stdin.Close()
wg.Done()

return;
//----

stdin.Write([]byte("version\n\n"))
stdin.Write([]byte("ciphers -v\n\n"))
stdin.Write([]byte("s_client -connect razeencheng.com:443"))
stdin.Close()
wg.Done()
}()

wg.Wait()
err := cmd.Wait()

if err != nil {
log.Printf("cmd wait %v", err)
return ""
}
return "";
//----------------------------------------------------------------


//奇怪,一定要在它本根目录下才行,大概是因为找不到 dat 文件 //否则 dat 文件也要加全路径
////cmd.Dir = GetCurrentPath() + "/map_http_upload"; //2022.06 加上执行的工作目录,兼容性会更高
//cmd.Dir = "D:/app_map/_src_map/map_http_upload/"; //暂时写死 //注意,要把 Palettes.cb 也放到这个目录中,否则颜色不对

//这样就可以把 php 命令行的结果重定向了
//cmd.Stdout = os.Stdout;
//cmd.Stderr = os.Stderr; //可选
//cmd.Start(); //这个不会等待

//cmd.Wait(); //等待进程结束//必须要有这个,否则会立即跳过去了

//----
//工作目录
cmd.Dir = work_path;
//cmd.Path = exe_path;
//cmd.Path = exe_path + "/" + s_cmd; //虽然奇怪,但是目前就是这样 //不行

//----
//创建获取命令输出管道
// stdout, err := cmd.StdoutPipe();
// if err != nil {
// fmt.Printf("Error:can not obtain stdout pipe for command:%s\n", err)
// return err.Error();
// }

// //----
// stderr, err := cmd.StderrPipe();
// if err != nil {
// fmt.Printf("Error:can not obtain stdout pipe for command:%s\n", err)
// return err.Error();
// }

/*
//执行命令
if err := cmd.Start(); err != nil {
fmt.Println("Error:The command is err,", err)
return err.Error();
}

//return "";

//----
//创建获取命令输出管道 //要放在开始之前
// stdout, err := cmd.StdoutPipe();
// if err != nil {
// fmt.Printf("Error:can not obtain stdout pipe for command:%s\n", err)
// return err.Error();
// }

// //----
// stderr, err := cmd.StderrPipe();
// if err != nil {
// fmt.Printf("Error:can not obtain stderr pipe for command:%s\n", err)
// return err.Error();
// }

//读取所有输出
bytes, err := ioutil.ReadAll(stdout)
if err != nil {
fmt.Println("ReadAll Stdout:", err.Error())
return err.Error();
}
fmt.Println(bytes);

//return "";

//不能全部读取,因为要一直输出
//stdout.Read()
//bytes, err := ioutil.ReadAll(stdout)
//参考 ReadAll(r Reader) ([]byte, error) {
buf := make([]byte, 0, 512)
for {

n, err := stdout.Read(buf);

if (n<1) { break; }

//b = b[:len(b)+n]
buf = buf[:n]; //截取为读取的字节
if err != nil {
if err == io.EOF {
err = nil
}//if 2
//return b, err

}else{
//如果是成功的读取

fmt.Printf("stdout:\n\n %s", buf);

}//if 1

//---- err 也要读取一下
n, err = stderr.Read(buf);

if (n<1) { break; }

//b = b[:len(b)+n]
buf = buf[:n]; //截取为读取的字节
if err != nil {
if err == io.EOF {
err = nil
}//if 2
//return b, err

}else{
//如果是成功的读取

fmt.Printf("stdout:\n\n %s", buf);

}//if 1

}//for //while
*/

//cmd.Output()
output, err := cmd.Output()
if err != nil {
//panic(err)
fmt.Println("wait:", err.Error());
return err.Error();
}
// 因为结果是字节数组,需要转换成string
fmt.Println("output:", string(output))


if err := cmd.Wait(); err != nil {
fmt.Println("wait:", err.Error())
return err.Error();
}

//fmt.Printf("stdout:\n\n %s", bytes);

//----

//return string(bytes);

return "ok";
}//



总数:0 页次:1/0 首页 尾页  
总数:0 页次:1/0 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1