Running a command in the background

I use the following code that executes the "npm install" command, now during debugging I see that the command takes about 10.15 seconds to execute (it depends on how many modules I have). I want this command to run in the background and the program will continue.

cmd := exec.Command(name ,args...)
cmd.Dir = entryPath

In debugging, I see that to go to the next tass line is about 10..15 sec ...

I have two questions:

  • How can i do this? since I want to do something in parallel ...
  • How can I find out when it ends? To provide additional logic related to this command, that is, after completion npm install, I need to do other things.
+6
source share
2 answers

While in general you need goroutines to run something parallel (or, rather, parallel), in the case of running an external command or application in this way you do not need to use goroutines (in fact, it is redundant).

This is because the one exec.Cmdused to run the commands has Cmd.Start()one that launches the specified command, but without waiting for its completion. That way, you can do other things while they are running in the background, and when you need to wait for completion (and process its result), you can call Cmd.Wait()(which blocks and waits for the command to complete).

Here's what it might look like:

cmd := exec.Command("npm", "install", "other_params")
cmd.Dir = entryPath

if err := cmd.Start(); err != nil {
    log.Printf("Failed to start cmd: %v", err)
    return
}

// Do other stuff while cmd runs in background:
log.Println("Doing other stuff...")

// And when you need to wait for the command to finish:
if err := cmd.Wait(); err != nil {
    log.Printf("Cmd returned error: %v", err)
}

Cmd.Start() Cmd.Run(), , " ". Cmd.Run() , Cmd.Start() Cmd.Wait().

, Cmd.Output() Cmd.CombinedOutput(), ( ). , Cmd.Stdout, / .

:

cmd := exec.Command("npm", "install", "other_params")
cmd.Dir = entryPath
buf := &bytes.Buffer{}
cmd.Stdout = buf

if err := cmd.Start(); err != nil {
    log.Printf("Failed to start cmd: %v", err)
    return
}

// Do other stuff while cmd runs in background:
log.Println("Doing other stuff...")

// And when you need to wait for the command to finish:
if err := cmd.Wait(); err != nil {
    log.Printf("Cmd returned error: %v", err)
    // You may decide to continue or return here...
}

fmt.Println("[OUTPUT:]", buf.String())

, / Cmd.Stderr. . Cmd.Stdout Cmd.Stderr, , :

Stdout Stderr , ==,
goroutine Write.

+8

, goroutines channels.

goroutine exec.Command. .

goroutine.

, , , . goroutine, , . , .

type Data struct {
    output []byte
    error  error
}

func runCommand(ch chan<- Data) {
    cmd := exec.Command("ls", "-la")
    data, err := cmd.CombinedOutput()
    ch <- Data{
        error:  err,
        output: data,
    }
}

func main() {
    c := make(chan Data)

    // This will work in background
    go runCommand(c)

    // Do other things here

    // When everything is done, you can check your background process result
    res := <-c
    if res.error != nil {
        fmt.Println("Failed to execute command: ", res.error)
    } else {
        // You will be here, runCommand has finish successfuly
        fmt.Println(string(res.output))
    }
}

:

, OP, .

: , . res: = < -c,

: . check

:

+7

All Articles