golang代码实例库

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3594|回复: 0

golang:执行shell命令4(非阻塞,实时逐行处理标准输出)

[复制链接]

82

主题

82

帖子

486

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
486
发表于 2021-12-23 23:23:18 | 显示全部楼层 |阅读模式
实例说明
我们经常需要执行本地shell命令,或者是执行其他二进制可执行文件
1)执行本地二进制可执行文件
2)非阻塞执行,不等待执行完成再继续
3)逐行实时处理标准输出内容,比如增加序号


实例代码
[Golang] 纯文本查看 复制代码
package main

import (
        "bufio"
        "fmt"
        "io"
        "os/exec"
        "strings"
)

// ExecShellNoBlock2 执行shell命令,非阻塞,即不等待执行结果
func ExecShellNoBlock2(cmd string) (string, error) {
        shell := exec.Command("/bin/bash", "-c", cmd)

        // 创建一个与标准输出相关联的管道
        stdout, err := shell.StdoutPipe()
        if err != nil {
                return "", err
        }

        // 1、执行命令,这里不会等待命令执行完成,调用start后,命令已经开始执行了
        err = shell.Start()
        if err != nil {
                return "", err
        }

        index := 0
        content := make([]string, 0)
        // 2、这里可以继续执行其他操作了,同时上面的shell命令也在执行中了
        reader := bufio.NewReader(stdout)
        for {
                // 记录行数
                index++

                line, rErr := reader.ReadString('\n')
                if rErr == io.EOF {
                        break
                }
                if rErr != nil {
                        // 错误传递到外面,告诉方法调用者,中间遇到了错误
                        err = rErr
                        break
                }
                //fmt.Println(fmt.Sprintf("%+v", []byte(line)))
                // [104 101 108 108 111 32 119 111 114 108 100 10]
                // 有些系统中,会有多余多换行符,如上面注释最后部分的10(ascii码中的10是换行),这里删除它
                line = strings.Trim(line, string([]byte{10}))

                // 打印这个内容,可以看出来是隔一秒打印一行的,即这个是实时处理返回输出的。
                // 这句话只是方便看清楚实时的处理过程,无实际意义
                fmt.Println(line)

                // 每一行内容增加序号,我们可以用我们实际代码来替换这里
                content = append(content, fmt.Sprintf("%d. %s", index, line))
        }

        // 这里才会等待命令执行完成
        // 为什么我们要等待脚本执行完成?如果不等待,如果我们这个测试程序的main函数执行完成了,但这个脚本还没有执行完成,会被立即终止掉
        // wait方法会自动关闭上面创建的管道
        shell.Wait()
        // 当然,我们完全可以不使用shell.Wait()等待脚本执行,完全可以像下面一样sleep 几秒钟来等待脚本执行完成。
        //time.Sleep(3 * time.Second)

        // 返回执行结果
        return strings.Join(content, "\n"), err
}

func main() {
        // 等待1秒,然后输出hello world
        cmd := "sleep 1;echo hello world;sleep 1;echo hello world;sleep 1;echo hello world"
        out, _ := ExecShellNoBlock2(cmd)
        fmt.Println(out)
        // 输出:
        // hello world
        // hello world
        // hello world
        // 1. hello world
        // 2. hello world
        // 3. hello world
}



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|golang代码实例库 ( 粤ICP备2021162396号 )

GMT+8, 2025-1-22 12:38 , Processed in 0.024838 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表