57

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?

0

4 Answers 4

65

For your shell script to be directly runnable you have to:

  1. Start it with #!/bin/sh (or #!/bin/bash, etc).

  2. 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)
Sign up to request clarification or add additional context in comments.

10 Comments

thanks. this seems to be working. however now I have a different problem - although the script takes about 1 min to run, the program does not wait for it to finish running. and so the execution continues without the export actually being written yet.. any ideas?
@orcaman how are you running it? exec.Command("/bin/sh", mongoToCsvSH).Output()?
yes. thing is, I have to wait for this sh to export the file before I continue to the next lines.
can we pass arguments to mongoToCsvSH in the above example?
@BenyaminJafari that looks to be the case per Richard Bright's answer. (adding this mostly for future readers)
|
13

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
}

1 Comment

what about adding arguments when /path/to/file.sh requires arguments?
6

You need to execute /bin/sh and pass the script itself as an argument.

Comments

2

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.