Go в примерах: Порождающие процессы (Spawning Processes)

Иногда наши программы Go должны порождать другие, не Go процессы. Например, подсветка синтаксиса на этом сайте реализуется путем запуска pygmentize процесса из программы Go. Давайте рассмотрим несколько примеров порождающих процессов из Go.

package main
import (
    "fmt"
    "io/ioutil"
    "os/exec"
)
func main() {

Мы начнем с простой команды, которая не принимает аргументов или ввода и просто печатает что-то на стандартный вывод. Хелпер exec.Command создает объект для представления этого внешнего процесса.

    dateCmd := exec.Command("date")

.Output - это еще один хелпер, который обрабатывает общий случай запуска команды, ожидаетее завершения и сбора выходных данных. Если ошибок не было, dateOut будет содержать байты с информацией о дате.

    dateOut, err := dateCmd.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println("> date")
    fmt.Println(string(dateOut))

Далее мы рассмотрим несколько более сложный случай, когда мы направляем данные во внешний процесс на его stdin и собираем результаты из его stdout.

    grepCmd := exec.Command("grep", "hello")

Здесь мы явно получаем каналы ввода-вывода, запускаем процесс, записываем в него некоторые входные данные, читаем полученный результат и, наконец, ожидаем завершения процесса.

    grepIn, _ := grepCmd.StdinPipe()
    grepOut, _ := grepCmd.StdoutPipe()
    grepCmd.Start()
    grepIn.Write([]byte("hello grep\ngoodbye grep"))
    grepIn.Close()
    grepBytes, _ := ioutil.ReadAll(grepOut)
    grepCmd.Wait()

Мы опускаем проверки ошибок в приведенном выше примере, но вы можете использовать обычный шаблон if err != nil для них. Мы также собираем только результаты StdoutPipe, но вы можете собирать StderrPipe точно таким же образом.

    fmt.Println("> grep hello")
    fmt.Println(string(grepBytes))

Обратите внимание, что при порождении команд нам нужно предоставить явно разграниченный массив команд и аргументов вместо возможности просто передать одну строку командной строки. Если вы хотите создать полную команду со строкой, вы можете использовать опцию -c в bash:

    lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
    lsOut, err := lsCmd.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println("> ls -a -l -h")
    fmt.Println(string(lsOut))
}

Порожденные программы возвращают вывод, который является таким же, как если бы мы запускали их непосредственно из командной строки.

$ go run spawning-processes.go 
> date
Wed Oct 10 09:53:11 PDT 2012
> grep hello
hello grep
> ls -a -l -h
drwxr-xr-x  4 mark 136B Oct 3 16:29 .
drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
-rw-r--r--  1 mark 1.3K Oct 3 16:28 spawning-processes.go

Следующий пример: Исполняющие процессы (Exec'ing Processes).