Launch a terminal command in Go that is defined as an alias - bash

I am writing a program in Go that sends some commands.
I can run any command that is in the $PATH.
I check that the command is runnable with the LookPath function.
path, err := exec.LookPath("pwd")
and then run it with the following command:
func Run(command string, args []string) string {
cmd := exec.Command(command, args...)
output, err := cmd.CombinedOutput()
if err != nil {
logging.PrintlnError(fmt.Sprint(err) + ": " + string(output))
return ""
}
return string(output)
}
The Run("pwd", "") is working
But if I am using an alias, it doesnt' work.
For instance, I have alias l='ls -lah' in my ~/.bash_aliases file, but when I want to run that command in Go, it doesn't work.
Run("l") is not working.
I have the following error message :
exec: "l": executable file not found in $PATH:
I tried as well to use another method to run some alias' command.
func RunCmd(cmd string) string {
out, err := exec.Command(cmd).Output()
if err != nil {
logging.PrintlnError("error occured")
logging.PrintlnError(fmt.Sprint(err))
}
fmt.Printf("%s", out)
return string(out)
}
But it is not working as well.
Do you know what function I can use to launch a command that is defined as an alias in my shell?
I tried to launch bash -c cmd but unfortunately as well.
Thanks

If you want to launch a command that is defined as an alias in your ~/.bashrc or~/.bash_aliases files, you can use the bash -c cmd command described in the other comments.
Nevertheless, you must implement it in a proper way in Go.
Here is the command:
exec.Command("/bin/bash", "-c", "aliasCmd "+ _alias_arguments)
However, you should not have your program to rely on a user defined alias. ;-)

Related

Executing a python script from Golang with arguments

I am trying to execute a python script ( which is used for accessing remote machines and run commands ) from Golang, it errors with "exit status 2"
out, err := exec.Command("/usr/local/opt/bin/python3.7", "/users/test.py -i 12.13.14.15 --cmd \"uptime && date\"").Output()
if err != nil {
fmt.Printf("%s", err)
} else {
fmt.Println("Command Successfully Executed")
output := string(out[:])
fmt.Println(output)
}
Output
exit status 2
thank you.
You are passing a single argument to the executable containing everything. Instead, you have to pass each argument separately:
out, err := exec.Command("/usr/local/opt/bin/python3.7", "/users/test.py", "-i", "12.13.14.15", "--cmd", "uptime && date").Output()

Command that works in terminal doesn't work with go exec.Command [duplicate]

This question already has an answer here:
calling command with some arguments works but not with others but works from console
(1 answer)
Closed 1 year ago.
I'm trying to attach to a go-ethereum node from a go script:
accountInfo:= fmt.Sprintf("attach %v --exec 'eth.getBalance(eth.accounts[0])'", connect)
//x, err := exec.Command("geth", accountInfo).Output() // returns 'Fatal: Unable to attach to remote geth: no known transport for URL scheme "c"'
x, err := exec.Command("geth", accountInfo).Output() // returns "invalid command: "attach ws://127.0.0.1:8101...." <--- rest of the metaData string
if err != nil {
fmt.Println(err)
}
This command works perfectly fine in terminal but it keeps telling me it's invalid when running it like this. This is making me go nuts.
From the os/exec documentation:
Unlike the "system" library call from C and other languages, the os/exec package intentionally does not invoke the system shell and does not expand any glob patterns or handle other expansions, pipelines, or redirections typically done by shells.
Since the arg ...string parameter of exec.Command() isn't processed by a shell, each argument is handed to the command exactly as specified. In your case, the entire content of metaData is provided to geth as a single argument.
You should instead create a slice of strings, each containing a single argument. And then provide that slice as the arg parameter using the ... notation.
Here's an example demonstrating this, using the uname command:
package main
import (
"fmt"
"os/exec"
)
func main() {
command := "uname"
argsString := "--kernel-name --machine"
argsSlice := []string{"--kernel-name", "--machine"}
// Equivalent command:
// $ uname "--kernel-name --machine"
fmt.Println("exec.Command(command, argsString)")
stringOutput, err := exec.Command(command, argsString).CombinedOutput()
if err != nil {
fmt.Printf("Failed: %s\n", err)
}
fmt.Printf("Output:\n%s\n", stringOutput)
// Equivalent command:
// $ uname --kernel-name --machine
fmt.Println("exec.Command(command, argsSlice)")
sliceOutput, err := exec.Command(command, argsSlice...).CombinedOutput()
if err != nil {
fmt.Printf("Failed: %s", err)
}
fmt.Printf("Output:\n%s\n", sliceOutput)
}
And it's otuput:
$ go run main.go
exec.Command(command, argsString)
Failed: exit status 1
Output:
uname: unrecognized option '--kernel-name --machine'
Try 'uname --help' for more information.
exec.Command(command, argsSlice)
Output:
Linux x86_64

exec.Command call java cli

How can I make the exec.Command command call a command from another file?
func main() {
fmt.Println("Iniciando...")
command := exec.Command("java -version")
command.Dir = "."
output, err := command.Output()
if err != nil {
fmt.Println("Erro: ", err)
}
fmt.Printf("%s", output)
}
Erro: exec: "java -version": executable file not found in $PATH
Each argument needs to be in its own separate string. Try exec.Command("java", "-version")

Start detached command with redirect to file

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.

Executing a Bash Script from Golang

I am trying to figure out a way to execute a script (.sh) file from Golang. I have found a couple of easy ways to execute commands (e.g. os/exec), but what I am looking to do is to execute an entire sh file (the file sets variables etc.).
Using the standard os/exec method for this does not seem to be straightforward: both trying to input "./script.sh" and loading the content of the script into a string do not work as arguments for the exec function.
for example, this is an sh file that I want to execute from Go:
OIFS=$IFS;
IFS=",";
# fill in your details here
dbname=testDB
host=localhost:27017
collection=testCollection
exportTo=../csv/
# get comma separated list of keys. do this by peeking into the first document in the collection and get his set of keys
keys=`mongo "$host/$dbname" --eval "rs.slaveOk();var keys = []; for(var key in db.$collection.find().sort({_id: -1}).limit(1)[0]) { keys.push(key); }; keys;" --quiet`;
# now use mongoexport with the set of keys to export the collection to csv
mongoexport --host $host -d $dbname -c $collection --fields "$keys" --csv --out $exportTo$dbname.$collection.csv;
IFS=$OIFS;
from the Go program:
out, err := exec.Command(mongoToCsvSH).Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("output is %s\n", out)
where mongoToCsvSH can be either the path to the sh or the actual content - both do not work.
Any ideas how to achieve this?
For your shell script to be directly runnable you have to:
Start it with #!/bin/sh (or #!/bin/bash, etc).
You have to make it executable, aka chmod +x script.
If you don't want to do that, then you will have to execute /bin/sh with the path to the script.
cmd := exec.Command("/bin/sh", mongoToCsvSH)
This worked for me
func Native() string {
cmd, err := exec.Command("/bin/sh", "/path/to/file.sh").Output()
if err != nil {
fmt.Printf("error %s", err)
}
output := string(cmd)
return output
}
You need to execute /bin/sh and pass the script itself as an argument.
This allows you to pass the arguments as well as get the output of the script in the Stdout or Stderr.
import (
"github.com/sirupsen/logrus"
"os"
"os/exec"
)
func Execute(script string, command []string) (bool, error) {
cmd := &exec.Cmd{
Path: script,
Args: command,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
c.logger.Info("Executing command ", cmd)
err := cmd.Start()
if err != nil {
return false, err
}
err = cmd.Wait()
if err != nil {
return false, err
}
return true, nil
}
Calling example:
command := []string{
"/<path>/yourscript.sh",
"arg1=val1",
"arg2=val2",
}
Execute("/<path>/yourscript.sh", command)

Resources