Функция exec.CommandContext
Функция exec.CommandContext создает новый экземпляр
структуры exec.Cmd для выполнения внешней команды,
но в отличие от exec.Command, она принимает первым
параметром контекст context.Context, который позволяет
управлять временем жизни процесса. Вторым параметром передается
путь к исполняемому файлу или имя команды, а последующие параметры
представляют аргументы командной строки.
Синтаксис
exec.CommandContext(ctx, name, arg...)
Функция возвращает указатель на структуру exec.Cmd,
которую можно настроить и запустить. В случае, если переданный
контекст будет отменен или истечет его таймаут, запущенный
процесс получит сигнал SIGKILL и завершится.
Пример - простой запуск команды
Давайте выполним команду echo с текстом "hello world" и получим ее вывод:
package main
import (
"context"
"fmt"
"os/exec"
)
func main() {
ctx := context.Background()
cmd := exec.CommandContext(ctx, "echo", "hello world")
output, err := cmd.Output()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(output))
}
Результат выполнения кода:
"hello world\n"
Пример - установка таймаута
Давайте запустим команду sleep на 5 секунд, но установим таймаут в 2 секунды:
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "sleep", "5")
err := cmd.Run()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Command finished successfully")
}
Результат выполнения кода:
"Error: signal: killed"
Пример - ручная отмена команды
Давайте запустим команду, которая выполняется долго, и отменим ее вручную через 1 секунду:
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(1 * time.Second)
cancel()
}()
cmd := exec.CommandContext(ctx, "sleep", "10")
err := cmd.Run()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Command finished successfully")
}
Результат выполнения кода:
"Error: signal: killed"
Пример - получение вывода и ошибок
Давайте выполним команду и обработаем как стандартный вывод, так и стандартный поток ошибок:
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "sh", "-c", "echo stdout; echo stderr >&2")
stdout, err := cmd.Output()
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
fmt.Println("Stderr:", string(exitErr.Stderr))
}
fmt.Println("Error:", err)
return
}
fmt.Println("Stdout:", string(stdout))
}
Результат выполнения кода:
"Stdout: stdout\n"
Смотрите также
-
функцию
exec.Command,
которая создает команду без контекста -
функцию
exec.Cmd.Run,
которая запускает команду и ожидает ее завершения -
функцию
exec.Cmd.Output,
которая запускает команду и возвращает стандартный вывод -
функцию
exec.ExitError,
которая представляет ошибку завершения команды с ненулевым кодом