Вы не проверяете ошибки в нескольких местах.
В некоторых случаях это на самом деле не вызывает проблем, но все же стоит проверить:
cmd.Start()
может вернуться ошибка, в этом случае команда никогда не выполнялась. (Это не настоящая проблема.)
Когда stdoutScanner.Scan()
возвращает false, stdoutScanner.Err()
может показывать ошибку. Если вы начнете проверять это, вы обнаружите некоторые ошибки:
2020/02/19 15:38:17 [stdout err] read |0: file already closed
Это не настоящая проблема, но - ага - это соответствует симптомам, которые вы видите: не все результаты были замечены. Теперь, почему чтение stdout
утверждает, что файл закрыт? Ну, откуда взялась stdout
? Отсюда:
stdout, err := cmd.StdoutPipe()
Взгляните на исходный код для этой функции , который заканчивается следующими строками:
c.closeAfterStart = append(c.closeAfterStart, pw)
c.closeAfterWait = append(c.closeAfterWait, pr)
return pr, nil
(и pr
возвращаемое значение для чтения канала). Хм: что может значить closeAfterWait
?
Теперь, вот ваши последние две строки в вашем l oop:
cmd.Wait()
wg.Wait()
То есть сначала мы ждем, пока cmd
Фини sh. (Когда cmd
заканчивается, что закрывается?) Затем мы ждем goroutine, который читает стандартный вывод cmd
в fini sh. (Хм, а что еще можно читать из pr
канала?)
Исправление теперь очевидно: поменяйте местами wg.Wait()
, который ждет, пока потребитель канала stdout завершит чтение sh с cmd.Wait()
, который ожидает выхода echo ...
и затем закрывает конец чтения канала. Если вы закроете, пока читатели все еще читают, они могут никогда не прочитать то, что вы ожидали.