Go за Прикладом: Запуск сторонніх процесів

Work in Progress / Сайт в процесі розробки

Інколи, нашій Go программі необхідно запустит інший, не “Go” процес. Наприклад, підсвітка синтаксису на цьому сайті реалізована пстороннім процесом pygmentize запущеним з Go програми. Давайте розглянумо кілька прикладів запуску процесів з Go.

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

Розпочнемо ми з простої команди, яка не приймає жодних аргументів або вводу, і яка лише друкує “щось” до stdout. Функція exec.Command створить об’єкт який представляє собою цей зовнішній процес.

    dateCmd := exec.Command("date")

.Output - інша функція, яка бере на себе управління загальними випадками запуску процесу, очікування його завершення та отримання виводу. Якщо помилок не було, зріз dateOut буде наповнено байтами відповіді проце date, який ми щойно викликали.

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

Тепер ми готові розглянути приклад, більш просунутого використання, де ми перенаправимо дані у поток введення зовнішнього процесу та отримаємо результати з його потоку виведення.

    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))

Зауважемо - коли ми породжуємо процеси нам необхідно надати чітко розділені команду і масив аргументів, напротивагу передачі всієї команди записаної в один рядок. Якщо ж вам, таки, кортить передати все одним рядком, скористайтесь bash‘овим параметром -c:

    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
Mon Jun 18 16:53:38 EEST 2018
> grep hello
hello grep
> ls -a -l -h
drwxr-xr-x  4 butuzov 136B Oct 3 16:29 .
drwxr-xr-x 91 butuzov 3.0K Oct 3 12:50 ..
-rw-r--r--  1 butuzov 1.3K Oct 3 16:28 spawning-processes.go

Наступний приклад: Заміна поточного процесу новим.