Running an executable on a Windows command prompt along with the arguments is just fine:
cgx_STATIC.exe -b C:\Users\m3\AppData\Local\Temp\shot-277325955.fbd
But when running the same executable through Golang, the executable becomes non-responsive after some of the output files are created by the executable.
// Run an executable and print its log into a file.
func RunWithLogFile(pthExe string, arg []string, fLog *os.File) error {
cmd := exec.Command(pthExe, arg...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return err
}
err = cmd.Start()
if err != nil {
return err
}
// Stream logs:
// https://stackoverflow.com/a/48849811/3405291
scannerOut := bufio.NewScanner(stdout)
scannerErr := bufio.NewScanner(stderr)
scannerOut.Split(bufio.ScanRunes)
scannerErr.Split(bufio.ScanRunes)
for scannerOut.Scan() {
_, err = fLog.WriteString(scannerOut.Text())
if err != nil {
return err
}
}
for scannerErr.Scan() {
_, err = fLog.WriteString(scannerErr.Text())
if err != nil {
return err
}
}
if scannerOut.Err() != nil {
return err
}
if scannerErr.Err() != nil {
return err
}
err = cmd.Wait()
return err
}
I was wondering if the above Go code is somehow buggy or not suitable for running executables?
Separate goroutines
As suggested by @BurakSerdar I read from stdout and stderr in separate goroutines, but the problem didn't get resolved:
// Run an executable and print its log into a file.
func RunWithLogFile(pthExe string, arg []string, fLog *os.File) error {
cmd := exec.Command(pthExe, arg...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return err
}
var wg sync.WaitGroup
wg.Add(2)
go streamToLogFile(stdout, fLog, &wg)
go streamToLogFile(stderr, fLog, &wg)
err = cmd.Start()
if err != nil {
return err
}
wg.Wait()
err = cmd.Wait()
return err
}
func streamToLogFile(output io.ReadCloser, fLog *os.File, wg *sync.WaitGroup) {
defer wg.Done()
scanner := bufio.NewScanner(output)
scanner.Split(bufio.ScanRunes)
for scanner.Scan() {
_, err := fLog.WriteString(scanner.Text())
if err != nil {
log.Printf("error: write to log file: %s", err.Error())
}
}
err := scanner.Err()
if err != nil {
log.Printf("error: write to log file: %s", err.Error())
}
}
forloops look kind of suspicious.