Using exec only starts program in background - go

I am trying to make a go program that calls another program (with a GUI) by command line.
Using os/exec package. The external program starts, but it always runs in the background. (Even if I try to start "Notepad.exe" or a .bat file which then calls the actual program.)
In the task manager you can see the process but there no way to interact with it.
Here's an example of code I've been experimenting with:
cmd := exec.Command("cmd.exe", "/C", "start", "\"\"", `Notepad.exe`)
log.Println("cmd.exe", "/C", "start", "\"\"", `Notepad.exe`)
cmd.Stdout = os.Stdout
if err := cmd.Start(); err != nil {
log.Println("Error: ", err)
}
Is there a way to alter the code so it starts "Notepad.exe" in a way it can be interacted with via the UI?
I am trying this with a program on Windows compiled on Mac.

You don't need that empty "" parameter, simply use:
cmd := exec.Command("cmd.exe", "/C", "start", "notepad.exe")
Also notepad.exe won't write anything to its standard output, so you don't need to set it. Simply run it like:
s := []string{"cmd.exe", "/C", "start", "notepad.exe"}
log.Println("Starting", s)
cmd := exec.Command(s[0], s[1:]...)
if err := cmd.Run(); err != nil {
log.Println("Error:", err)
}

Related

how to get log info when i run cmd.start(xx.exe)

source code is:
//this code run in parent process
cmd:=exec.Command("cmd","/c","./child.exe")
if e:=cmd.Start();e!=nil{
//todo handle error
}
//child.exe handle task maybe long time
os.Exit() //notice!!! parent process will kill itself because test.exe will rm parent process
My problem is test.exe have anything log info in cmd.
More or less like this:
cmd := exec.Command("cmd", "/c", "./child.exe")
out := bytes.NewBuffer(nil)
cmd.Stdout = out
if err := cmd.Run(); err != nil {
}
fmt.Println(out.String())

Write file from exec.Command

I am trying to write a file from a bash command into a file in Go.
Note there are several reasons for using Go over bash here: I have some more logic such as parsing configuration files, I would like to run that code for multiple DBs in parallele and finally performing some more complex data manipulation after.
dumpStr := fmt.Sprintf("pg_dump -U %s -h %s %s | gzip", DbUserName, DbHost, DbName)
cmd := exec.Command("bash", "-c", dumpStr)
cmd.Env = append(cmd.Env, "PGPASSWORD="+DbPassword)
outfile, err := os.Create(DbName + ".gz")
if err != nil {
panic(err)
}
outfile = cmd.Stdout
defer outfile.Close()
err = cmd.Start()
if err != nil {
panic(err)
}
cmd.Wait()
However, I am getting an emtpy result.
I am getting data if I am executing dumpStr from the CLI but not from that code...
What am I missing?
As Flimzy said, you're not capturing the output of pg_dump. You can do that with Go, or you can use pg_dump-s --file. It can also compress with --compress so no need to pipe to gzip. Then there's no need for bash and you can avoid shell quoting issues.
cmd := exec.Command(
"pg_dump",
"--compress=9",
"--file="+DbName + ".gz",
"-U"+DbUserName,
"-h"+DbHost,
DbName,
)
log.Print("Running pg_dump...")
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
Much simpler and more secure.
For illustration here's how you'd do it all in Go.
Use Cmd.StdoutPipe to get an open IO reader to pg_dump's stdout. Then use io.Copy to copy from stdout to your open file.
#Peter points out that since Cmd.Stdout is an io.Reader it's simpler to assign the open file to cmd.Stdout and let cmd write to it directly.
// Same as above, but no --file.
cmd := exec.Command(
"pg_dump",
"--compress=9",
"-U"+DbUserName,
"-h"+DbHost,
DbName,
)
// Open the output file
outfile, err := os.Create(DbName + ".gz")
if err != nil {
log.Fatal(err)
}
defer outfile.Close()
// Send stdout to the outfile. cmd.Stdout will take any io.Writer.
cmd.Stdout = outfile
// Start the command
if err = cmd.Start(); err != nil {
log.Fatal(err)
}
log.Print("Waiting for command to finish...")
// Wait for the command to finish.
if err = cmd.Wait(); err != nil {
log.Fatal(err)
}
In addition, you're only checking if the command started, not if it successfully ran.
From the docs for Cmd.Start.
Start starts the specified command but does not wait for it to complete.
The Wait method will return the exit code and release associated resources once the command exits.
You're checking cmd.Start for an error, but not cmd.Wait. Checking the error from cmd.Start only means the command started. If there is an error while the program is running you won't know what it is.
You need to actually use the output of your command. You're not doing that. To do so, use the StdoutPipe method, then you can copy the stdout from your program, into your file.

Start a detached process on Windows using Golang

I have a Golang code which must run a detached child process.
The Linux version of my implementation using syscall.ForkExec like this.
syscall.ForkExec(my_program, []string{}, nil)
But I can't found Windows implementation. I have found a proposition using START /B.
cmd := exec.Command("START", "/B", my_program)
cmd.Start()
Unfortunately, START can't be found and I have no other solution using Golang.
start is not a standalone application, it's an (internal) command of the Windows command line interpreter (cmd.exe) (details: Command line reference / Start), so you need a "shell" to run the start command.
Use cmd.exe with the /C parameter, and pass start and your application to run.
Like in this example:
s := []string{"cmd.exe", "/C", "start", `c:\path\to\your\app\myapp.exe`}
cmd := exec.Command(s[0], s[1:]...)
if err := cmd.Run(); err != nil {
log.Println("Error:", err)
}
Or without the command slice:
cmd := exec.Command("cmd.exe", "/C", "start", `c:\path\to\your\app\myapp.exe`)
if err := cmd.Run(); err != nil {
log.Println("Error:", err)
}
You may also pass the /b param to start like this if you don't want a terminal window for the launched application:
cmd := exec.Command("cmd.exe", "/C", "start", "/b", `c:\path\to\your\app\myapp.exe`)
if err := cmd.Run(); err != nil {
log.Println("Error:", err)
}
It's not clear to me what you mean by detached. If you mean in the sense, "don't wait for program to finish", you don't need a shell for that:
package main
import "os/exec"
func main() {
exec.Command("firefox", "google.com/search?q=golang").Start()
}
https://golang.org/pkg/os/exec#Cmd.Start

Programmatic way to call go tools

Is there a way to call the Go tools (like go build) programmatically from within another Go program with a library call and to get more structured output compared to the text output from the command line invocation?
If you're trying to run build programmatically you can also use the os/exec package.
func runBuild() {
cmd := exec.Command("go", "build", "./main.go")
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
}
You can pass other flags too. E.g: the buildmode flag
cmd := exec.Command("go", "build", "-buildmode=plugin", "./main.go")
Reference: https://golang.org/pkg/os/exec/
Within another go program it is possible to execute console commands using the os/exec package like so:
func main (){
cmd := exec.Command("go run lib/main.go")
if err := cmd.Run(); err != nil{
log.Fatal(err)
}
}
I don't see this being very useful though.

Go: Run External Python script

I have tried following the Go Docs in order to call a python script which just outputs "Hello" from GO, but have failed until now.
exec.Command("script.py")
or I've also tried calling a shell script which simply calls the python script, but also failed:
exec.Command("job.sh")
Any ideas how would I achieve this?
EDIT
I solved following the suggestion in the comments and adding the full path to exec.Command().
Did you try adding Run() or Output(), as in:
exec.Command("script.py").Run()
exec.Command("job.sh").Run()
You can see it used in "How to execute a simple Windows DOS command in Golang?" (for Windows, but the same idea applies for Unix)
c := exec.Command("job.sh")
if err := c.Run(); err != nil {
fmt.Println("Error: ", err)
}
Or, with Output() as in "Exec a shell command in Go":
cmd := exec.Command("job.sh")
out, err := cmd.Output()
if err != nil {
println(err.Error())
return
}
fmt.Println(string(out))
First of all do not forget to make your python script executable (permissions and #!/usr/local/bin/python at the beginning).
After this you can just run something similar to this (notice that it will report you errors and standard output).
package main
import (
"log"
"os"
"os/exec"
)
func main() {
cmd := exec.Command("script.py")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Println(cmd.Run())
}
Below worked for me on Windows 10
python := path.Clean(strings.Join([]string{os.Getenv("userprofile"), "Anaconda3", "python.exe"}, "/"))
script := "my_script.py"
cmd := exec.Command("cmd", python, script)
out, err := cmd.Output()
fmt.Println(string(out))
if err != nil {
log.Fatal(err)
}

Resources