如何通过Go程序调用Graphviz执行Dot脚本生成图片?
dot from Go Hey there! Let's break down why you're getting exit code 3 from the dot command and how to fix it.
First off, exit code 3 from Graphviz's dot typically means it's receiving invalid arguments—and that's exactly what's happening here. The problem is how you're trying to handle output redirection with > in your exec.Command call.
Why Your Current Code Fails
Go's os/exec package runs commands directly, not through a shell. That means when you pass ">", "/path/to/hello.png" as arguments to dot, it doesn't interpret the > as a redirection instruction—it treats it as a literal filename. dot can't find a file named > and throws an error, hence exit code 3.
Solution 1: Use Go's Stdout Redirection (Recommended)
The cleanest and safest way to capture the output is to use Go's built-in cmd.Stdout to pipe the command's output directly to a file. Here's the adjusted code:
package main import ( "fmt" "os" "os/exec" ) func main() { path, err := exec.LookPath("dot") if err != nil { fmt.Printf("Couldn't locate the dot command: %v\n", err) return } // Create the output file we want to write to outputFile, err := os.Create("/Users/arafat/Desktop/dev/go/src/github.com/Arafatk/dataviz/hello.png") if err != nil { fmt.Printf("Failed to create output file: %v\n", err) return } defer outputFile.Close() // Make sure we close the file when done // Set up the dot command without any redirection arguments cmd := exec.Command(path, "-Tpng", "/Users/arafat/Desktop/dev/go/src/github.com/Arafatk/dataviz/DotExamples/arraylist.dot") cmd.Stdout = outputFile // Redirect the command's stdout to our file err = cmd.Run() fmt.Println("Path to dot:", path) if err != nil { fmt.Printf("Command execution failed: %v\n", err) return } fmt.Println("Success! PNG image generated.") }
This approach avoids shell overhead, is more secure (no risk of shell injection if paths ever come from user input), and gives you more control over the I/O flow.
Solution 2: Run via Shell (If You Prefer)
If you really want to use shell-style redirection, you can execute the entire command through a shell like bash using the -c flag. Just make sure to properly quote your paths to avoid issues with spaces:
package main import ( "fmt" "os/exec" ) func main() { dotInputPath := "/Users/arafat/Desktop/dev/go/src/github.com/Arafatk/dataviz/DotExamples/arraylist.dot" pngOutputPath := "/Users/arafat/Desktop/dev/go/src/github.com/Arafatk/dataviz/hello.png" // Build the full shell command with quoted paths shellCmd := fmt.Sprintf("dot -Tpng %q > %q", dotInputPath, pngOutputPath) // Run the command through bash cmd := exec.Command("bash", "-c", shellCmd) err := cmd.Run() if err != nil { fmt.Printf("Command failed: %v\n", err) return } fmt.Println("PNG image generated successfully!") }
Give either of these a try, and your dot command should run without exit code 3.
内容的提问来源于stack exchange,提问作者ArafatK

