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
Related
I'm looking for a way to launch ssh in a terminal from a golang program.
func main() {
cmd := exec.Command("ssh", "user#192.168.0.17", "-p", "2222")
err := cmd.Run()
if err != nil {
panic(err)
}
}
This works great until I enter the correct password, then the program exits. I guess when authentified, another ssh script in launched, but I can't figure out how to solve this. I have searched some infos about it but all I found is how to create a ssh session in go, and I would like to avoid this, if possible.
You should pass in stdin, stdout, and stderr:
package main
import (
"os"
"os/exec"
)
func main() {
cmd := exec.Command("ssh", "user#192.168.0.17", "-p", "2222")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
panic(err)
}
}
I have found another way to solve my issue, by using :
binary, lookErr := exec.LookPath("ssh")
if lookErr != nil {
panic(lookErr)
}
syscall.Exec(binary, []string{"ssh", "user#192.168.0.17", "-p", "2222"}, os.Environ())
This will close the program's process and launch ssh on another one.
Thanks for helping me !
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)
}
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.
I'm trying to start a command in a detached process so that it can continue after go program exits. I need to redirect the output of the command to a file.
What I need is something like this:
func main() {
command := exec.Command("/tmp/test.sh", ">", "/tmp/out")
if err := command.Start(); err != nil {
fmt.Fprintln(os.Stderr, "Command failed.", err)
os.Exit(1)
}
fmt.Println("Process ID:", command.Process.Pid)
}
Obviously such redirect doesn't work. As I immediately exit from the program after starting the long running command, I cannot open a file and bind it to the Stdout.
Is there any way to achieve such a redirect?
You may start a shell which executes your command / app, and you may redirect its output to a file. The shell will continue to run and execute your script / app even if your Go app exits.
Example:
cmd := exec.Command("sh", "-c", "/tmp/test.sh > /tmp/out")
if err := cmd.Start(); err != nil {
panic(err)
}
fmt.Println("Process ID:", cmd.Process.Pid)
Test it with this simple Go app (replace /tmp/test.sh with the name of the executable binary you compile this into):
package main
import ("fmt"; "time")
func main() {
for i := 0; i < 10; i++ {
fmt.Printf("%d.: %v\n", i, time.Now())
time.Sleep(time.Second)
}
}
This app simply prints a line to the standard output once every second. You can see how the output file is being written e.g. with tail -f /tmp/out.
Note that you may use other shells to execute your scripts to your liking (and to what the test.sh script dictates).
For example to use bash:
cmd := exec.Command("/bin/bash", "-c", "/tmp/test.sh > /tmp/out")
// rest is unchanged
Note that the command to be executed by the shell is passed as a single string argument, and it is not broken down into multiple as you would do it if you were to execute it directly in the command prompt.
Maybe you can try to use this: https://stackoverflow.com/a/28918814/2728768
Opening a file (and os.File implements io.Writer), and then passing it as the command.Stdout could do the trick:
func main() {
command := exec.Command("./tmp/test.sh")
f, err := os.OpenFile("/tmp/out", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("error opening file: %v", err)
}
defer f.Close()
// On this line you're going to redirect the output to a file
command.Stdout = f
if err := command.Start(); err != nil {
fmt.Fprintln(os.Stderr, "Command failed.", err)
os.Exit(1)
}
fmt.Println("Process ID:", command.Process.Pid)
}
Not sure this could be a viable solution for your case. I've tried it locally and it seems working... remember that your user should be able to create/update the file.
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)
}