Complex command in exec.Command() - bash

I want to exec this command:
docker exec -it demoContainer bash -c "pip freeze" > "requirements.txt"
But don't find any example of this kind of complex commands with pipes, and output writes.
I tryed this:
cmd := exec.Command("docker", "exec -it demoContainer bash -c \"pip freeze\" > \"requirements.txt\"")
_, err = cmd.CombinedOutput()
And:
cmd := exec.Command("docker", "exec", "-it", "demoContainer", "bash", "-c", "pip freeze", ">", "scheduleDeploy/requirements.txt")
_, err = cmd.CombinedOutput()
But always crash with the following output:
Error: Exit status 1
Edit
Updates with answers ideas:
err = exec.Command("sh", "-c","'docker exec -it demoContainer bash -c 'pip freeze' > 'requirements.txt''").Run()
Output:
Exit error status 2

You don't have to use the shell for redirection, you can just let Go do it:
package main
import (
"os"
"os/exec"
)
func main() {
f, e := os.Create("requirements.txt")
if e != nil {
panic(e)
}
defer f.Close()
c := exec.Command(
"docker", "exec", "-it", "demoContainer", "bash", "-c", "pip freeze",
)
c.Stdout = f
c.Run()
}

The > redirection is a "shell" thing, not an "exec" thing. You will need to do one of "run bash, with the command you want executed" or "open a file, set the resulting os.File as the Stdout of the exec.Command, before starting it".
Either would probably solve the issue you are facing.
To use the "bash -c" version, something like:
exec.Command("bash", "-c", `docker exec -it demoContainer bash -c "pip freeze" > requirements.txt`)

Related

Run a docker container inside a Go server

I am trying to run a docker container in a Go server with using exec.Command.
Here is my code to run:
entrypoint := "/bin/bash"
run := fmt.Sprintf("docker run -a stdout -a stderr --rm %s %s %s", env, image, args)
cmd := exec.Command(entrypoint, "-c", run)
if err := cmd.Start(); err != nil {
return err
}
where env is something like:
-e KEY=VALUE
However, I get an error such as:
/bin/bash: docker run ... : No such file or directory
Then, I added double-quotes to the beginning and the end of docker command:
cmd := exec.Command(entrypoint, "-c", "\""+run+"\"")
This time, I can run command /bin/bash -c "docker run ..." in my Zsh terminal. However Go still throws the same error.
What should I do?
You are passing the docker run command and all its arguments as a single argument. Instead, try this:
cmd := exec.Command(entrypoint, "-c", "docker", "run", "-a", "stdout", "-a", "stderr", "--rm", <break up env>, image, args)

exec.Command with bash -c does not return stdout

Executing the following program, out is an empty slice of type []uint8.
package main
import (
"context"
"log"
"os/exec"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "bash", "-c", "python3", "-c", "print('hello')")
out, _ := cmd.Output()
log.Println(out)
}
However, if I run without bash -c, I get the expected output.
This is a trivial example where bash -c isn't needed, but in the real world, my app is invoking a python script which imports several packages, and without bash -c, I get "module not found" errors from python.
What am I doing wrong here? How can I capture the stdout contents?
bash -c should be followed by one string argument with the command to execute, then bash will do the argument processing.
cmd := exec.CommandContext(ctx, "bash", "-c", "python3 -c 'print(\"hello\")'")

Is there any way we can execute a multiple commands in exec.Command?

I am trying to execute set of commands in Go using exec.Command(). Where I am trying to detach Gluster peer using Docker Exec.
fmt.Println("About to execute gluster peer detach")
SystemdockerCommand := exec.Command("sh", "-c", "docker exec ", "9aa1124", " gluster peer detach ", "192.168.1.1", " force")
var out bytes.Buffer
var stderr bytes.Buffer
SystemdockerCommand.Stdout = &out
SystemdockerCommand.Stderr = &stderr
err := SystemdockerCommand.Run()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
}
fmt.Println("System Docker exec : " + out.String())
I was expecting a result as "no peer to detatch". But got
exit status 1: "docker exec" requires at least 2 arguments.
Since you have used sh -c, the next parameter should be the full command or commands:
SystemdockerCommand := exec.Command("sh", "-c", "docker exec 9aa1124 gluster peer detach 192.168.1.1 force")
More generally, as in here:
cmd := exec.Command("/bin/sh", "-c", "command1 param1; command2 param2; command3; ...")
err := cmd.Run()
See this example:
sh := os.Getenv("SHELL") //fetch default shell
//execute the needed command with `-c` flag
cmd := exec.Command(sh, "-c ", `docker exec 9aa1124 ...`)
Or this one, putting your commands in a string first:
cmd := "cat /proc/cpuinfo | egrep '^model name' | uniq | awk '{print substr($0, index($0,$4))}'"
out, err := exec.Command("bash","-c",cmd).Output()
if err != nil {
return fmt.Sprintf("Failed to execute command: %s", cmd)
}
multipass exec kube-node-one -- bash -c "ls && ls -a"
Is there any way we can execute a multiple commands in exec.Command
No.

os.Exec and /bin/sh: executing multiple commands

I've run into an issue with the os/exec library. I want to run a shell and pass it multiple commands to run, but it's failing when I do. Here's my test code:
package main
import (
"fmt"
"os/exec"
)
func main() {
fmt.Printf("-- Test 1 --\n`")
command1 := fmt.Sprintf("\"%s\"", "pwd") // this one succeeds
fmt.Printf("Running: %s\n", command1)
cmd1 := exec.Command("/bin/sh", "-c", command1)
output1,err1 := cmd1.CombinedOutput()
if err1 != nil {
fmt.Printf("error: %v\n", err1)
return
}
fmt.Printf(string(output1))
fmt.Printf("-- Test 2 --\n")
command2 := fmt.Sprintf("\"%s\"", "pwd && pwd") // this one fails
fmt.Printf("Running: %s\n", command2)
cmd2 := exec.Command("/bin/sh", "-c", command2)
output2,err2 := cmd2.CombinedOutput()
if err2 != nil {
fmt.Printf("error: %v\n", err2)
return
}
fmt.Printf(string(output2))
}
When running this I get an error 127 on the second example. It seems like it's looking for a literal "pwd && pwd" command instead of evaluating it as a script.
If I do the same thing from the command line it works just fine.
$ /bin/sh -c "pwd && pwd"
I'm using Go 1.4 on OS X 10.10.2.
the quotes are for your shell where you typed the command line, they should not be included when programatically launching an app
just make this change and it will work:
command2 := "pwd && pwd" // you don't want the extra quotes

Executing docker command using golang exec fails

I am using cmd.go (see below) to execute a docker command but it fails. I do the following steps to execute and get the following error.
go build
sudo ./cmd
Output:
docker run -v ~/exp/a.out:/a.out ubuntu:14.04 /a.out -m 10m
2014/10/16 14:32:12 exit status 1
On the other hand running directly as
sudo docker run -v ~/exp/a.out:/a.out ubuntu:14.04 /a.out -m 10m
results in the correct output of a.out.
Hello World
This is the code of cmd.go. How can I get it to work? Thanks!
package main
import (
"fmt"
"log"
"os/exec"
"strings"
)
func ExampleCmd_Output() {
//out, err := exec.Command("date", "--version").Output() // This works
//out, err := exec.Command("docker", "--version").Output() // This works
//out, err := exec.Command(cmd, "images").Output() // Even docker images command works!
cmd := "docker"
cmdArgs := []string{"run", "-v", "~/exp/a.out:/a.out", "ubuntu:14.04", "/a.out", "-m", "10m"}
fmt.Println(cmd + " " + strings.Join(cmdArgs, " "))
out, err := exec.Command(cmd, cmdArgs...).Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", out)
}
func main() {
ExampleCmd_Output()
}
EDIT: After a comment, I tried executing the command "docker images". It works if I run the executable with sudo. That is, I am using the following line in the code now.
out, err := exec.Command(cmd, "images").Output()
After doing go build and running "sudo ./cmd", I get the output of docker images command. However, without sudo, I still get exit status 1. But with docker run command above even with sudo, I don't get an output.
Thanks to Os Exec Sudo Command in Go, I am now able to do what I want.
func main() {
cmdStr := "sudo docker run -v ~/exp/a.out:/a.out ubuntu:14.04 /a.out -m 10m"
out, _ := exec.Command("/bin/sh", "-c", cmdStr).Output()
fmt.Printf("%s", out)
}
Output:
Hello World

Resources