clq
浏览(377) +
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";
}//
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.