Понякога се налага нашите програми да породят1 други процеси.
import (
"errors"
"fmt"
"io"
"os/exec"
)
func main() {
Да започнем с проста команда, която не приема податки или вход, а просто
отпечатва нещо на стандартния изход. Помощната функция 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))
Output и други методи на Command връщат *exec.Error ако бъдат
възпрепятствани при изпълнението на командата (например грешен пѫт), и
*exec.ExitError, ако командата се изпълни, но излезе с код различен от
нула.
_, err = exec.Command("date", "-x").Output()
if err != nil {
if e, ok := errors.AsType[*exec.Error](err); ok {
fmt.Println("Провалено изпълнение:", e)
} else if e, ok := errors.AsType[*exec.ExitError](err); ok {
exitCode := e.ExitCode()
fmt.Println("Код на изхода =", exitCode)
} else {
panic(err)
}
}
Сега да разгледаме по-сложен случай, в който подаваме данни на външния процес по неговия стандартен вход и събираме произведеното от процеса от неговия стандартен изход.
grepCmd := exec.Command("grep", "hello")
Тук изрично боравим с входноизходните потоци (тръби)1, пускаме процеса, пишем някакви данни във входа, четем изхода му и накрая чакаме процеса да приключи.
grepIn, _ := grepCmd.StdinPipe()
grepOut, _ := grepCmd.StdoutPipe()
grepCmd.Start()
grepIn.Write([]byte("hello grep\ngoodbye grep"))
grepIn.Close()
grepBytes, _ := io.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))
Пускане на програма, която не изчакваме да приключи. (бел. прев.)
zombie := exec.Commanddd(bash, -c,
date >>out.txt; sleep 2; date >> out.txt)
zombie.Start()
}
Пуснатите програми връщат изход както ако бихме ги били пуснали направо на командния ред.
$ go run spawning-processes.go
> date
17.06.2026 (ср) 0:40:32 EEST
date не приема флаг -x, така че ще приключи с ненулев изходен код, което
означава грешка.
Код на изхода = 1
> grep hello
hello grep
> ls -a -l -h
общо 24K
drwxr-xr-x 2 berov berov 4,0K 17 юни 00:37 .
drwxr-xr-x 87 berov berov 4,0K 17 яну 14:27 ..
-rw-rw-r-- 1 berov berov 4,7K 17 юни 00:37 spawning-processes.go
-rw-rw-r-- 1 berov berov 53 15 юни 23:32 spawning-processes.hash
-rw-rw-r-- 1 berov berov 481 20 май 01:41 spawning-processes.sh
Следващ пример: Изпълнение на процеси.