在Golang中执行curl bash命令并实时读取输出
在Golang中执行curl bash命令并实时读取输出 您好,我想通过 Go 语言运行一些 curl bash 脚本,并向用户实时显示这些脚本的输出。
例如,我想在 Go 中运行 curl -Lso- bench.sh | bash 并向用户显示实时输出,我该如何实现?
我已经尝试了以下方法:
package main
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strings"
)
实际上,我想通过 Go 运行一些 bash 脚本和二进制文件,并向用户显示输出(实时输出)。如果逐行读取并显示给用户也可以,但输出应该能快速显示给用户。
我不希望像 bash 脚本执行完毕后才显示输出那样。因为 bash 脚本会安装库和软件包,可能需要一些时间,所以我希望向用户实时显示 bash 脚本的输出。
更多关于在Golang中执行curl bash命令并实时读取输出的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我认为你需要重写这个命令,使其不使用 |。
我没有任何头绪,它应该是什么样子。
也许把它拆分成两个命令?…
更多关于在Golang中执行curl bash命令并实时读取输出的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
您可以考虑开发一个守护进程,它可以作为处理请求和响应的 AJAX 接口。
func main() {
cmd := exec.Command(/* your command */)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
}
试试这个。
gucio321:
func main() { cmd := exec.Command(/* your command */) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { log.Fatalf("cmd.Run() failed with %s\n", err) } }
这个方法有效,谢谢,但是无法运行 curl -Lso- bench.sh | bash。
在Go中执行外部命令并实时读取输出,可以通过exec.Command结合管道读取实现。以下是两种实现方式:
方法1:使用Scanner逐行读取(推荐)
package main
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strings"
)
func executeCommandWithRealtimeOutput(command string, args ...string) error {
cmd := exec.Command(command, args...)
// 获取标准输出管道
stdout, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("创建标准输出管道失败: %v", err)
}
// 获取标准错误管道
stderr, err := cmd.StderrPipe()
if err != nil {
return fmt.Errorf("创建标准错误管道失败: %v", err)
}
// 启动命令
if err := cmd.Start(); err != nil {
return fmt.Errorf("启动命令失败: %v", err)
}
// 创建读取器
stdoutReader := bufio.NewReader(stdout)
stderrReader := bufio.NewReader(stderr)
// 实时读取输出
done := make(chan bool)
go func() {
for {
line, err := stdoutReader.ReadString('\n')
if err != nil {
if err != io.EOF {
fmt.Printf("读取标准输出错误: %v\n", err)
}
break
}
fmt.Print(line)
}
done <- true
}()
go func() {
for {
line, err := stderrReader.ReadString('\n')
if err != nil {
if err != io.EOF {
fmt.Printf("读取标准错误错误: %v\n", err)
}
break
}
fmt.Print(line)
}
done <- true
}()
// 等待goroutine完成
<-done
<-done
// 等待命令执行完成
if err := cmd.Wait(); err != nil {
return fmt.Errorf("命令执行失败: %v", err)
}
return nil
}
func main() {
// 执行curl命令
err := executeCommandWithRealtimeOutput("bash", "-c", "curl -Lso- bench.sh | bash")
if err != nil {
fmt.Printf("执行失败: %v\n", err)
os.Exit(1)
}
}
方法2:使用io.Copy直接复制输出
package main
import (
"fmt"
"io"
"os"
"os/exec"
"sync"
)
func executeCommandWithRealtimeOutput2(command string, args ...string) error {
cmd := exec.Command(command, args...)
// 获取标准输出和标准错误管道
stdout, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("创建标准输出管道失败: %v", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
return fmt.Errorf("创建标准错误管道失败: %v", err)
}
// 启动命令
if err := cmd.Start(); err != nil {
return fmt.Errorf("启动命令失败: %v", err)
}
var wg sync.WaitGroup
wg.Add(2)
// 实时复制标准输出到控制台
go func() {
defer wg.Done()
_, err := io.Copy(os.Stdout, stdout)
if err != nil && err != io.EOF {
fmt.Printf("复制标准输出错误: %v\n", err)
}
}()
// 实时复制标准错误到控制台
go func() {
defer wg.Done()
_, err := io.Copy(os.Stderr, stderr)
if err != nil && err != io.EOF {
fmt.Printf("复制标准错误错误: %v\n", err)
}
}()
// 等待复制完成
wg.Wait()
// 等待命令执行完成
if err := cmd.Wait(); err != nil {
return fmt.Errorf("命令执行失败: %v", err)
}
return nil
}
func main() {
// 执行curl命令
err := executeCommandWithRealtimeOutput2("bash", "-c", "curl -Lso- bench.sh | bash")
if err != nil {
fmt.Printf("执行失败: %v\n", err)
os.Exit(1)
}
}
方法3:使用exec.CommandContext支持超时控制
package main
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"time"
)
func executeCommandWithTimeout(command string, args ...string) error {
// 设置30秒超时
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, command, args...)
// 获取标准输出和标准错误管道
stdout, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("创建标准输出管道失败: %v", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
return fmt.Errorf("创建标准错误管道失败: %v", err)
}
// 启动命令
if err := cmd.Start(); err != nil {
return fmt.Errorf("启动命令失败: %v", err)
}
// 实时读取输出
go io.Copy(os.Stdout, stdout)
go io.Copy(os.Stderr, stderr)
// 等待命令完成
if err := cmd.Wait(); err != nil {
if ctx.Err() == context.DeadlineExceeded {
return fmt.Errorf("命令执行超时")
}
return fmt.Errorf("命令执行失败: %v", err)
}
return nil
}
func main() {
// 执行curl命令
err := executeCommandWithTimeout("bash", "-c", "curl -Lso- bench.sh | bash")
if err != nil {
fmt.Printf("执行失败: %v\n", err)
os.Exit(1)
}
}
关键点说明:
- 使用
StdoutPipe()和StderrPipe():分别获取命令的标准输出和标准错误管道 - 在
cmd.Start()后立即读取:确保在命令执行过程中就能读取到输出 - 使用goroutine并发读取:同时读取stdout和stderr,避免阻塞
- 使用
io.Copy或bufio.Scanner:两种方式都能实现实时输出,io.Copy更简单,Scanner可以逐行处理
对于你的具体需求,建议使用方法1或方法2,它们都能实现实时显示curl -Lso- bench.sh | bash的输出。

