Go - 使用 goroutines 执行 Bash 命令 n 次并存储并打印其结果
Go - Execute a Bash Command n Times using goroutines and Store & Print its result
总的来说,我对 Golang
很陌生,我正在尝试执行 bash command with its arguments n times
,然后将 Output
存储在一个变量中,然后 Print
它。
我只能做一次,或者像下面这样使用 loops
:
package main
import (
"fmt"
"os/exec"
"os"
"sync"
)
func main() {
//Default Output
var (
cmdOut []byte
err error
)
//Bash Command
cmd := "./myCmd"
//Arguments to get passed to the command
args := []string{"arg1", "arg2", "arg3"}
//Execute the Command
if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil {
fmt.Fprintln(os.Stderr, "There was an error running "+cmd+" "+args[0]+args[1]+args[2], err)
os.Exit(1)
}
//Store it
sha := string(cmdOut)
//Print it
fmt.Println(sha)
}
这很好用,我可以轻松阅读 output
。
现在,我想使用 goroutines
.
重复同样的操作 n
次
我尝试采用与回答 How would you define a pool of goroutines to be executed at once in Golang? 的人完全相同的方法,但我无法做到这一点。
这就是我到目前为止所尝试的:
package main
import (
"fmt"
"os/exec"
"sync"
)
func main() {
//Bash Command
cmd := "./myCmd"
//Arguments to get passed to the command
args := []string{"arg1", "arg2", "arg3"}
//Common Channel for the goroutines
tasks := make(chan *exec.Cmd, 64)
//Spawning 4 goroutines
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
for cmd := range tasks {
cmd.Run()
}
wg.Done()
}()
}
//Generate Tasks
for i := 0; i < 10; i++ {
tasks <- exec.Command(cmd, args...)
//Here I should somehow print the result of the latter command
}
close(tasks)
// wait for the workers to finish
wg.Wait()
fmt.Println("Done")
}
但是,我真的不知道如何存储已执行命令的 i-result
并打印它。
我该如何实现?
提前致谢,如需对问题进行任何澄清,请发表评论。
因此以下内容可以解决您的问题
您可以调用Cmd.Output() 来获取命令的输出。
否则你可以将 Cmd.StdOutPipe 管道连接到 byte.Buffer
示例并从中阅读。
你的 goroutine 逻辑是错误的。它只会执行 4 次,因为等待组将是 Done() 并且 main 将退出。您关闭 main 的通道以向工作人员发出退出 for range 循环的信号是正确的。 wg.Done 应该在那之后调用,所以我推迟了它。
当您使用 go 命令执行匿名函数时,尽量不要从父范围捕获任何内容。它可能导致灾难。而不是找出你想要的参数并将它们传递给函数。
`
package main
import (
"fmt"
"os/exec"
"sync"
)
func main() {
cmd := "./foo.sh"
//Arguments to get passed to the command
args := []string{"bar", "baz"}
//Common Channel for the goroutines
tasks := make(chan *exec.Cmd, 64)
//Spawning 4 goroutines
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func(num int, w *sync.WaitGroup) {
defer w.Done()
var (
out []byte
err error
)
for cmd := range tasks { // this will exit the loop when the channel closes
out, err = cmd.Output()
if err != nil {
fmt.Printf("can't get stdout:", err)
}
fmt.Printf("goroutine %d command output:%s", num, string(out))
}
}(i, &wg)
}
//Generate Tasks
for i := 0; i < 10; i++ {
tasks <- exec.Command(cmd, args...)
}
close(tasks)
// wait for the workers to finish
wg.Wait()
fmt.Println("Done")
}
`
总的来说,我对 Golang
很陌生,我正在尝试执行 bash command with its arguments n times
,然后将 Output
存储在一个变量中,然后 Print
它。
我只能做一次,或者像下面这样使用 loops
:
package main
import (
"fmt"
"os/exec"
"os"
"sync"
)
func main() {
//Default Output
var (
cmdOut []byte
err error
)
//Bash Command
cmd := "./myCmd"
//Arguments to get passed to the command
args := []string{"arg1", "arg2", "arg3"}
//Execute the Command
if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil {
fmt.Fprintln(os.Stderr, "There was an error running "+cmd+" "+args[0]+args[1]+args[2], err)
os.Exit(1)
}
//Store it
sha := string(cmdOut)
//Print it
fmt.Println(sha)
}
这很好用,我可以轻松阅读 output
。
现在,我想使用 goroutines
.
n
次
我尝试采用与回答 How would you define a pool of goroutines to be executed at once in Golang? 的人完全相同的方法,但我无法做到这一点。
这就是我到目前为止所尝试的:
package main
import (
"fmt"
"os/exec"
"sync"
)
func main() {
//Bash Command
cmd := "./myCmd"
//Arguments to get passed to the command
args := []string{"arg1", "arg2", "arg3"}
//Common Channel for the goroutines
tasks := make(chan *exec.Cmd, 64)
//Spawning 4 goroutines
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
for cmd := range tasks {
cmd.Run()
}
wg.Done()
}()
}
//Generate Tasks
for i := 0; i < 10; i++ {
tasks <- exec.Command(cmd, args...)
//Here I should somehow print the result of the latter command
}
close(tasks)
// wait for the workers to finish
wg.Wait()
fmt.Println("Done")
}
但是,我真的不知道如何存储已执行命令的 i-result
并打印它。
我该如何实现?
提前致谢,如需对问题进行任何澄清,请发表评论。
因此以下内容可以解决您的问题
您可以调用Cmd.Output() 来获取命令的输出。 否则你可以将 Cmd.StdOutPipe 管道连接到 byte.Buffer 示例并从中阅读。
你的 goroutine 逻辑是错误的。它只会执行 4 次,因为等待组将是 Done() 并且 main 将退出。您关闭 main 的通道以向工作人员发出退出 for range 循环的信号是正确的。 wg.Done 应该在那之后调用,所以我推迟了它。
当您使用 go 命令执行匿名函数时,尽量不要从父范围捕获任何内容。它可能导致灾难。而不是找出你想要的参数并将它们传递给函数。
`
package main
import (
"fmt"
"os/exec"
"sync"
)
func main() {
cmd := "./foo.sh"
//Arguments to get passed to the command
args := []string{"bar", "baz"}
//Common Channel for the goroutines
tasks := make(chan *exec.Cmd, 64)
//Spawning 4 goroutines
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func(num int, w *sync.WaitGroup) {
defer w.Done()
var (
out []byte
err error
)
for cmd := range tasks { // this will exit the loop when the channel closes
out, err = cmd.Output()
if err != nil {
fmt.Printf("can't get stdout:", err)
}
fmt.Printf("goroutine %d command output:%s", num, string(out))
}
}(i, &wg)
}
//Generate Tasks
for i := 0; i < 10; i++ {
tasks <- exec.Command(cmd, args...)
}
close(tasks)
// wait for the workers to finish
wg.Wait()
fmt.Println("Done")
}
`