# #go
Вопрос:
Я выполняю команду exec.Command("cf api https://something.com/")
, и иногда требуется ответ. Но при выполнении этой команды не происходит никакого ожидания, а выполняется и немедленно идет дальше. Мне нужно подождать несколько секунд или пока не будет получен вывод. Как этого добиться?
func TestCMDExex(t *testing.T) {
expectedText := "Success"
cmd := exec.Command("cf api https://something.com/")
cmd.Dir = "/root//"
out, err := cmd.Output()
if err != nil {
t.Fail()
}
assert.Contains(t, string(out), expectedText)
}
Ответ №1:
Во-первых: правильный способ создания cmd-это:
cmd := exec.Command("cf", "api", "https://something.com/")
Каждый аргумент дочерней программы должен быть отдельной строкой. Таким образом, вы также можете передавать аргументы, содержащие пробелы в них. Например, выполнение программы с:
cmd := exec.Command("cf", "api https://something.com/")
передаст один аргумент командной строки cf
, который является «api https://something.com/», в то время как передача двух строк приведет к передаче двух аргументов «api» и «https://something.com/».
В вашем исходном коде вы пытаетесь выполнить программу, имя которой «cf api https://something.com/».
Затем вы можете запустить его и получить результат:
out, err:=cmd.Output()
Комментарии:
1. Они @бурак , Спасибо! это сработало. Похоже ли это на то, что нам нужно заключать каждый текст в кавычки?
Ответ №2:
Вы можете использовать группу ожидания go. Это функция, которую мы будем запускать в каждой гороутине. Обратите внимание, что группа ожидания должна передаваться функциям по указателю. По возвращении сообщите группе ожидания, что мы закончили. Сон для имитации дорогостоящей задачи. (удалите его в вашем случае) Эта группа ожидания используется для ожидания завершения всех запущенных здесь гороутов. Блокируйте до тех пор, пока счетчик группы ожидания не вернется к 0; все работники уведомлены, что они закончили.
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d startingn", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d donen", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i {
wg.Add(1)
go worker(i, amp;wg)
}
wg.Wait()
}
Ответ №3:
Это можно решить с помощью подпрограммы, канала и оператора select. Приведенный ниже пример кода также выполняет обработку ошибок:
func main() {
type output struct {
out []byte
err error
}
ch := make(chan output)
go func() {
// cmd := exec.Command("sleep", "1")
// cmd := exec.Command("sleep", "5")
cmd := exec.Command("false")
out, err := cmd.CombinedOutput()
ch <- output{out, err}
}()
select {
case <-time.After(2 * time.Second):
fmt.Println("timed out")
case x := <-ch:
fmt.Printf("program done; out: %qn", string(x.out))
if x.err != nil {
fmt.Printf("program errored: %sn", x.err)
}
}
}
Выбрав один из 3 вариантов exec.Command()
, вы можете увидеть, как код ведет себя 3 возможными способами: тайм-аут, обычное завершение подпроцесса, завершение подпроцесса с ошибкой.
Как обычно при использовании goroutines, необходимо позаботиться о том, чтобы они прекратили работу, чтобы избежать утечки ресурсов.
Обратите также внимание, что если выполняемый подпроцесс является интерактивным или если он выводит свою последовательность в stdout и важно видеть вывод во время его выполнения , то лучше использовать cmd.Run()
, удалить структуру и сообщать только об ошибке в канале.