Метод exec.Cmd.Start

Метод exec.Cmd.Start запускает внешний процесс, используя параметры, заданные в структуре exec.Cmd. В отличие от метода Run, который запускает процесс и ожидает его завершения, метод Start возвращает управление сразу после запуска процесса. Метод возвращает ошибку, если процесс не удалось запустить. После вызова Start необходимо вызвать метод Wait, чтобы дождаться завершения процесса и освободить системные ресурсы.

Синтаксис

gocmd := exec.Command(name, arg...)
err := cmd.Start()

Пример

Давайте запустим команду echo в асинхронном режиме и дождемся ее завершения с помощью метода Wait:

gopackage main

import (
  "exec"
  "fmt"
  "log"
)

func main() {
  cmd := exec.Command("echo", "Hello, World!")
  err := cmd.Start()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println("Process started")
  err = cmd.Wait()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println("Process finished")
}

Результат выполнения кода:

go"Process started"
"Hello, World!"
"Process finished"

Пример

Давайте запустим длительный процесс и проверим, что управление возвращается немедленно, а процесс продолжает выполняться в фоне:

gopackage main

import (
  "exec"
  "fmt"
  "log"
  "time"
)

func main() {
  cmd := exec.Command("sleep", "3")
  err := cmd.Start()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println("Command started at", time.Now().Format("15:04:05"))
  err = cmd.Wait()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println("Command finished at", time.Now().Format("15:04:05"))
}

Результат выполнения кода:

go"Command started at 14:30:15"
"Command finished at 14:30:18"

Как видно из примера, между запуском и завершением процесса прошло примерно 3 секунды, но сообщение о запуске вывелось сразу, без ожидания завершения команды.

Пример

Давайте запустим процесс с перенаправлением стандартного вывода в буфер и прочитаем результат после завершения:

gopackage main

import (
  "bytes"
  "exec"
  "fmt"
  "log"
)

func main() {
  var stdout bytes.Buffer
  cmd := exec.Command("ls", "-l")
  cmd.Stdout = &stdout
  err := cmd.Start()
  if err != nil {
    log.Fatal(err)
  }
  err = cmd.Wait()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println(stdout.String())
}

Результат выполнения кода:

go"total 0\n-rw-r--r-- 1 user user 0 Jan 1 00:00 file1.txt\n-rw-r--r-- 1 user user 0 Jan 1 00:00 file2.txt\n"

Пример

Давайте обработаем ошибку, которая возникает при попытке запустить несуществующую команду:

gopackage main

import (
  "exec"
  "fmt"
  "log"
)

func main() {
  cmd := exec.Command("nonexistent-command")
  err := cmd.Start()
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  err = cmd.Wait()
  if err != nil {
    log.Fatal(err)
  }
}

Результат выполнения кода:

go"Error: exec: \"nonexistent-command\": executable file not found in $PATH"

Важно отметить, что метод Start возвращает ошибку только в случае проблем с запуском процесса. Если процесс запустился, но завершился с ненулевым кодом возврата, ошибку вернет метод Wait, а не Start.

Смотрите также

  • метод exec.Cmd.Run,
    который запускает процесс и ожидает его завершения
  • метод exec.Cmd.Wait,
    который ожидает завершения процесса и освобождает ресурсы
  • функцию exec.Command,
    которая создает структуру Cmd для выполнения внешней команды
  • метод exec.Cmd.Output,
    который выполняет команду и возвращает стандартный вывод