Im using the following code which run command against binary and need to provide output
if I run the command ftr get apps in the in my mac I got
[app1 apps2]
Now I copy the binary to the test data folder
and run the code below and I want to get the apps, currenlty there is no error but Im not getting also the data, what could be missing here?
Cmd := exec.Command("ftr", "get", "apps")
Cmd.Dir = "./testdata/"
err := Cmd.Start()
fmt.Println(err)
bytes, e := Cmd.Output()
fmt.Println(bytes, e)
You won't directly have an output, since the commands takes some time before it writes in stdout/stderr, so you need to basically wait for something to come out.
The way you can do it is by using bufio.NewScanner, like this:
package main
import (
"bufio"
"fmt"
"os/exec"
"strings"
)
func main() {
args := "get apps"
cmd := exec.Command("ftr", strings.Split(args, " ")...)
cmd.Dir = "./testdata/"
stdout, _ := cmd.StdoutPipe()
cmd.Start()
scanner := bufio.NewScanner(stdout)
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
cmd.Wait()
}
If your command writes on stderr instead of stdout, you might need to use cmd.StderrPipe instead of cmd.Stdoutpipe in order to get the output.
Calling both Start and Output is redundant.
Output runs the command and returns its standard output.
Start is used to run the command asynchronously. Simply remove that call:
cmd := exec.Command("ftr", "get", "apps")
cmd.Dir = "./testdata/"
b, err := cmd.Output()
fmt.Println(string(b), err)
Related
How to read/manipulate the input from a connection that is passed to a command stdin?
For example, given the following code.
c, _ := net.Dial("tcp", somehost)
cmd := exec.Command("/bin/sh")
cmd.Stdin, cmd.Stdout, cmd.Stderr = c, c, c
cmd.Run()
How would it be possible to reverse the string from the connection before it is passed to the cmd.Stdin or how could I parse the string and not pass it on to cmd.Stdin?
Ive considered reading from the connection with bufio and then passing it to Command second argument, the params, but I was hoping for a better solution that does not require me to handle all the different cases for args input in a command, but instead just passing it on to Stdin after analysing the input
Ok since you mentioned in comments that "my real issue is how to intercept the input from the connection, parse it and parse it to the Stdin of the command. Seems when I do cmd.Run() I block and hence cant really continously parse"
Here is how I will do it:
import (
"io"
"os"
"os/exec"
)
func main() {
//All errors are not checked
cmd := exec.Command("/bin/sh")
cmdStdin, _ := cmd.StdinPipe()
go func() {
defer cmdStdin.Close()
//here you will need to loop on reading the connection,
//for simplicity lets assume you do that & receive data
//let says you got ls from connection
cmdStdin.Write([]byte("ls\n"))
}()
cmdStdout, _ := cmd.StdoutPipe()
go io.Copy(os.Stdout, cmdStdout)
cmd.Run()
}
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)
}
I've got a command line tool written in Golang and I need to start vim from it. However it's not working, and there's not any error or much else to work with. I've reduced the code to just this:
package main
import (
"fmt"
"os/exec"
)
func main() {
cmd := exec.Command("vim", "test.txt")
err := cmd.Run()
fmt.Println(err)
}
When I run this, I can see the vim process for a 2-3 seconds but the application doesn't actually open. Then the program simply exits (and the vim process closes) with an "exit status 1".
I've also tried this to capture stderr:
package main
import (
"bytes"
"fmt"
"os/exec"
)
func main() {
cmd := exec.Command("vim", "test.txt")
var stderr bytes.Buffer
cmd.Stderr = &stderr
err := cmd.Run()
fmt.Println(err)
fmt.Println(stderr)
}
But in this case, the program gets stuck indefinitely.
Any idea what could be the issue?
Pass on stdin and stdout from the calling program which, provided it was run from a terminal (likely for a command line program) will start vim for you and return control when the user has finished editing the file.
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
cmd := exec.Command("vim", "test.txt")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
err := cmd.Run()
fmt.Println(err)
}
VIM needs a proper terminal and detects the absence of one.
If you use the StderrPipe and read it while vim is running you will see this:
2014/02/02 20:25:49 Vim: Warning: Output is not to a terminal
2014/02/02 20:25:49 Vim: Warning: Input is not from a terminal
Example for reading stderr while executing (on play):
func logger(pipe io.ReadCloser) {
reader := bufio.NewReader(pipe)
for {
output, err := reader.ReadString('\n')
if err != nil {
log.Println(err)
return
}
log.Print(string(output))
}
}
pipe, err := cmd.StderrPipe()
go logger(pipe)
cmd.Run()
For vim to run you probably need to emulate a terminal.
Maybe goat (doc) can help you out:
tty := term.NewTTY(os.Stdin)
cmd := exec.Command("vim", "test.txt")
cmd.Stdin = t
cmd.Stdout = t
// ...
How to run a simple Windows command?
This command:
exec.Command("del", "c:\\aaa.txt")
.. outputs this message:
del: executable file not found in %path%
What am I doing wrong?
I got the same error as you.
But dystroy is correct: You can't run del or any other command built into cmd because there is no del.exe file (or any other del-executable for that matter).
I got it to work with:
package main
import(
"fmt"
"os/exec"
)
func main(){
c := exec.Command("cmd", "/C", "del", "D:\\a.txt")
if err := c.Run(); err != nil {
fmt.Println("Error: ", err)
}
}
You need a Windows cmd to execute your dir command.
Try this :
cmd := exec.Command("cmd", "/C", "dir").Output()
(sorry, no Windows computer to check it right now)
Found another solution too. Create a batch file that contains the following: del c:\aaa.txt
Then call it like this:
exec.Command("c:\\del.bat").Run()
In case you need the output of cmd:
if c, err := exec.Command("cmd","/c","del","a.txt").CombinedOutput(); err != nil {
log.Fatal(err)
} else {
fmt.Printf("%s\n", c)
}
Ok let's see, according to the documentation, in windows, processes receive commands as a single line string and do some parsing of their own. Exec's Command function builds the command string by combining all arguments together using CommandLineToArgvW, that despite being the most common quoting algorithm doesn't work for every application. Applications like msiexec.exe and cmd.exe use an incompatible unquoting algorithm, hence the extra mile.
Heres a different example using powershell
package main
import (
"os/exec"
"fmt"
"log"
)
func main() {
out, err := exec.Command("powershell","remove-item","aaa.txt").Output()
if err != nil {
log.Fatal(err)
} else {
fmt.Printf("%s",out)
}
you can try use github.com/go-cmd/cmd module.
because golang can not use syscall by default.
example:
import (
"fmt"
"time"
"github.com/go-cmd/cmd"
)
func main() {
// Start a long-running process, capture stdout and stderr
findCmd := cmd.NewCmd("find", "/", "--name", "needle")
statusChan := findCmd.Start() // non-blocking
ticker := time.NewTicker(2 * time.Second)
// Print last line of stdout every 2s
go func() {
for range ticker.C {
status := findCmd.Status()
n := len(status.Stdout)
fmt.Println(status.Stdout[n-1])
}
}()
// Stop command after 1 hour
go func() {
<-time.After(1 * time.Hour)
findCmd.Stop()
}()
// Check if command is done
select {
case finalStatus := <-statusChan:
// done
default:
// no, still running
}
// Block waiting for command to exit, be stopped, or be killed
finalStatus := <-statusChan
}
c := exec.Command("cmd", "/C", "dir", "d:\\")
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
c.Run()
I'm writing a program in Go that executes a server like program (also Go). Now I want to have the stdout of the child program in my terminal window where I started the parent program. One way to do this is with the cmd.Output() function, but this prints the stdout only after the process has exited. (That's a problem because this server-like program runs for a long time and I want to read the log output)
The variable out is of type io.ReadCloser and I don't know what I should do with it to achieve my task, and I can't find anything helpful on the web on this topic.
func main() {
cmd := exec.Command("/path/to/my/child/program")
out, err := cmd.StdoutPipe()
if err != nil {
fmt.Println(err)
}
err = cmd.Start()
if err != nil {
fmt.Println(err)
}
//fmt.Println(out)
cmd.Wait()
}
Explanation to the code: uncomment the Println function to get the code to compile, I know that Println(out io.ReadCloser) is not a meaningful function.
(it produces the output &{3 |0 <nil> 0} ) These two lines are just required to get the code to compile.
Now I want to have the stdout of the child program in my terminal
window where I started the parent program.
No need to mess with pipes or goroutines, this one is easy.
func main() {
// Replace `ls` (and its arguments) with something more interesting
cmd := exec.Command("ls", "-l")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
}
I believe that if you import io and os and replace this:
//fmt.Println(out)
with this:
go io.Copy(os.Stdout, out)
(see documentation for io.Copy and for os.Stdout), it will do what you want. (Disclaimer: not tested.)
By the way, you'll probably want to capture standard-error as well, by using the same approach as for standard-output, but with cmd.StderrPipe and os.Stderr.
For those who don't need this in a loop, but would like the command output to echo into the terminal without having cmd.Wait() blocking other statements:
package main
import (
"fmt"
"io"
"log"
"os"
"os/exec"
)
func checkError(err error) {
if err != nil {
log.Fatalf("Error: %s", err)
}
}
func main() {
// Replace `ls` (and its arguments) with something more interesting
cmd := exec.Command("ls", "-l")
// Create stdout, stderr streams of type io.Reader
stdout, err := cmd.StdoutPipe()
checkError(err)
stderr, err := cmd.StderrPipe()
checkError(err)
// Start command
err = cmd.Start()
checkError(err)
// Don't let main() exit before our command has finished running
defer cmd.Wait() // Doesn't block
// Non-blockingly echo command output to terminal
go io.Copy(os.Stdout, stdout)
go io.Copy(os.Stderr, stderr)
// I love Go's trivial concurrency :-D
fmt.Printf("Do other stuff here! No need to wait.\n\n")
}