首页 > 解决方案 > 休眠过程,直到在 Go 中完成

问题描述

我正在尝试自动化 Go 中的流程。我已经能够实现线程并相应地执行该过程,但是输出是混合和匹配的。

我想知道是否有一种方法可以显示程序产生的输出并根据程序的过程。因此,如果任务 A 在任务 B 之前完成,我们会在 B 之前显示 A 的输出,反之亦然。

package main

import (
    "fmt"
    "log"
    "os"
    "os/exec"
    "sync"
)

var url string
var wg sync.WaitGroup

func nikto() {
    cmd := exec.Command("nikto", "-h", url)
    cmd.Stdout = os.Stdout
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    wg.Done()
}

func whois() {

    cmd := exec.Command("whois", "google.co")
    cmd.Stdout = os.Stdout
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    wg.Done()
}
func main() {
    fmt.Printf("Please input URL")
    fmt.Scanln(&url)
    wg.Add(1)
    go nikto()
    wg.Add(1)
    go whois()
    wg.Wait()
}

标签: linuxbashgo

解决方案


在您的进程中,您将os.Stdout文件描述符直接传递给您调用以运行子进程的命令。这意味着子进程的 STDOUT 管道将直接连接到 Go 程序的标准输出,并且如果两个子进程同时写入,则可能会交错。


解决这个问题的最简单方法是在 Go 程序中缓冲来自子进程的 STDOUT 管道的输出,以便在打印时截取输出并进行控制。

包中的Cmd类型os/exec提供了一个函数调用Output(),它将调用子进程并以字节片的形式返回 STDOUT 的内容。您的代码可以轻松调整以实现此模式并处理结果,例如:

func whois() {
    cmd := exec.Command("whois", "google.co")
    out, err := cmd.Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(out)
    wg.Done()
}

输出交错

如果使用fmt包中的函数打印输出,则不能保证并发调用fmt.Println不会被交错。

为了防止交错,您可以选择序列化对 STDOUT 的访问,或者使用对并发使用安全的记录器(例如log包)。下面是在 Go 进程中序列化访问 STDOUT 的示例:

package main

import (
    "fmt"
    "log"
    "os/exec"
    "sync"
)

var url string

func nikto(outChan chan<- []byte) {
    cmd := exec.Command("nikto", "-h", url)
    bs, err := cmd.Output()
    if err != nil {
        log.Fatal(err)
    }
    outChan <- bs
}

func whois(outChan chan<- []byte) {
    cmd := exec.Command("whois", "google.com")
    bs, err := cmd.Output()
    if err != nil {
        log.Fatal(err)
    }
    outChan <- bs
}

func main() {
    outChan := make(chan []byte)

    fmt.Printf("Please input URL")
    fmt.Scanln(&url)
    go nikto(outChan)
    go whois(outChan)

    for i := 0; i < 2; i++ {
        bs := <-outChan
        fmt.Println(string(bs))
    }
}

推荐阅读