问题
I have a function like this:
package main
import (
"fmt"
)
// PrintSomething prints some thing
func PrintSomething() {
fmt.Println("print something")
}
func main() {
PrintSomething()
}
How do I wrap PrintSomething to another function call CaptureSomething to save the string "print something" to a variable and return it?
回答1:
Create pipe and set stdout to the pipe writer. Start a goroutine to copy the pipe reader to a buffer. When done, close the pipe writer and wait for goroutine to complete reading. Return the buffer as a string.
// capture replaces os.Stdout with a writer that buffers any data written
// to os.Stdout. Call the returned function to cleanup and get the data
// as a string.
func capture() func() (string, error) {
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
done := make(chan error, 1)
save := os.Stdout
os.Stdout = w
var buf strings.Builder
go func() {
_, err := io.Copy(&buf, r)
r.Close()
done <- err
}()
return func() (string, error) {
os.Stdout = save
w.Close()
err := <-done
return buf.String(), err
}
}
Use it like this:
done := capture()
fmt.Println("Hello, playground")
capturedOutput, err := done()
if err != nil {
// handle error
}
playground example
回答2:
For example,
package main
import (
"fmt"
"io/ioutil"
"os"
)
// PrintSomething prints some thing
func PrintSomething() {
fmt.Println("print something")
}
func CaptureSomething() (string, error) {
defer func(stdout *os.File) {
os.Stdout = stdout
}(os.Stdout)
out, err := ioutil.TempFile("", "stdout")
if err != nil {
return "", err
}
defer out.Close()
outname := out.Name()
os.Stdout = out
PrintSomething()
err = out.Close()
if err != nil {
return "", err
}
data, err := ioutil.ReadFile(outname)
if err != nil {
return "", err
}
os.Remove(outname)
return string(data), nil
}
func main() {
s, err := CaptureSomething()
if err != nil {
fmt.Println(err)
} else {
fmt.Print(s)
}
}
Playground: https://play.golang.org/p/O2kSegxYeGy
Output:
print something
回答3:
Use one of these, whichever works for you:
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
)
func PrintSomething() {
fmt.Println("print something")
}
func PrintSomethingBig() {
for i := 0; i < 100000; i++ {
fmt.Println("print something")
}
}
func PrintSomethingOut(out io.Writer) {
fmt.Fprintln(out, "print something to io.Writer")
}
func PrintSomethingString() string {
return fmt.Sprintln("print something into a string")
}
// not thread safe
// modified by zlynx@acm.org from original at http://craigwickesser.com/2015/01/capture-stdout-in-go/
func captureStdout(f func()) string {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
go func() {
f()
w.Close()
}()
buf := &bytes.Buffer{}
// Will complete when the goroutine calls w.Close()
io.Copy(buf, r)
// Clean up.
os.Stdout = old
r.Close()
return buf.String()
}
func main() {
str1 := &strings.Builder{}
str2 := PrintSomethingString()
PrintSomethingOut(str1)
PrintSomethingOut(os.Stdout)
str3 := captureStdout(PrintSomething)
str4 := captureStdout(PrintSomethingBig)
fmt.Println("string 1 is", str1)
fmt.Println("string 2 is", str2)
fmt.Println("string 3 is", str3)
fmt.Println("string 4 len", len(str4))
}
来源:https://stackoverflow.com/questions/51183462/how-to-copy-os-stdout-output-to-string-variable