10

I'm having trouble figuring out how to run multiple commands using the os/exec package. I've trolled the net and stackoverflow and haven't found anything that works for me case. Here's my source:

package main

import (
    _ "bufio"
    _ "bytes"
    _ "errors"
    "fmt"
    "log"
    "os"
    "os/exec"
    "path/filepath"
)

func main() {
    ffmpegFolderName := "ffmpeg-2.8.4"
    path, err := filepath.Abs("")
    if err != nil {
        fmt.Println("Error locating absulte file paths")
        os.Exit(1)
    }

    folderPath := filepath.Join(path, ffmpegFolderName)

    _, err2 := folderExists(folderPath)
    if err2 != nil {
        fmt.Println("The folder: %s either does not exist or is not in the same directory as make.go", folderPath)
        os.Exit(1)
    }
    cd := exec.Command("cd", folderPath)
    config := exec.Command("./configure", "--disable-yasm")
    build := exec.Command("make")

    cd_err := cd.Start()
    if cd_err != nil {
        log.Fatal(cd_err)
    }
    log.Printf("Waiting for command to finish...")
    cd_err = cd.Wait()
    log.Printf("Command finished with error: %v", cd_err)

    start_err := config.Start()
    if start_err != nil {
        log.Fatal(start_err)
    }
    log.Printf("Waiting for command to finish...")
    start_err = config.Wait()
    log.Printf("Command finished with error: %v", start_err)

    build_err := build.Start()
    if build_err != nil {
        log.Fatal(build_err)
    }
    log.Printf("Waiting for command to finish...")
    build_err = build.Wait()
    log.Printf("Command finished with error: %v", build_err)

}

func folderExists(path string) (bool, error) {
    _, err := os.Stat(path)
    if err == nil {
        return true, nil
    }
    if os.IsNotExist(err) {
        return false, nil
    }
    return true, err
}

I want to the command like I would from terminal. cd path; ./configure; make So I need run each command in order and wait for the last command to finish before moving on. With my current version of the code it currently says that ./configure: no such file or directory I assume that is because cd path executes and in a new shell ./configure executes, instead of being in the same directory from the previous command. Any ideas? UPDATE I solved the issue by changing the working directory and then executing the ./configure and make command

err = os.Chdir(folderPath)
    if err != nil {
        fmt.Println("File Path Could not be changed")
        os.Exit(1)
    }

Still now i'm curious to know if there is a way to execute commands in the same shell.

reticentroot
  • 3,612
  • 2
  • 22
  • 39

1 Answers1

41

If you want to run multiple commands within a single shell instance, you will need to invoke the shell with something like this:

cmd := exec.Command("/bin/sh", "-c", "command1; command2; command3; ...")
err := cmd.Run()

This will get the shell to interpret the given commands. It will also let you execute shell builtins like cd. Note that this can be non-trivial to substitute in user data to these commands in a safe way.

If instead you just want to run a command in a particular directory, you can do that without the shell. You can set the current working directory to execute the command like so:

config := exec.Command("./configure", "--disable-yasm")
config.Dir = folderPath
build := exec.Command("make")
build.Dir = folderPath

... and continue on like you were before.

James Henstridge
  • 42,244
  • 6
  • 132
  • 114
  • Thank you for your answer. I especially appreciate your first suggestion. I stumbled on your second suggestion and currently using it. – reticentroot Dec 25 '15 at 00:23
  • @James I tried the way you suggested. command := exec.Command("echo *tar.gz | xargs -n1 tar zxf") command.Dir = pathFinal cmdErr := command.Run() This is not working for me on the otherhand, command := "cd "+pathFinal+"; "+"echo *tar.gz | xargs -n1 tar zxf" cmd := exec.Command("/bin/sh", "-c", command) This is working. I want to implement it the first way. I don't know why it is not working. – supriya May 10 '17 at 10:48
  • It throws error: Failed to untar file: exec: "echo *tar.gz | xargs -n1 tar zxf": executable file not found in $PATH – supriya May 10 '17 at 10:59
  • 1
    @supriya: globs and pipes are shell features rather than things interpreted by the kernel. You'll either need to do those parts from Go, or explicitly call the shell and let it interpret things for you. You can pipe together commands by the `StdoutPipe()` of the first command to `Stdin` of the second command. – James Henstridge May 12 '17 at 08:17