在进程完成后读取标准错误输出。

huangapple go评论80阅读模式
英文:

Read stderr after process finished

问题

我使用内存中的一些数据(来自HTML表单上传/网络服务器)调用imagemagick的convert命令。这个工作正常,但是我想在出现错误时获取convert的错误输出。我该如何做到这一点?

这是我的代码:

package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"os/exec"
	"path/filepath"
)

func runImagemagick(data []byte, destfilename string) error {
	data_buf := bytes.NewBuffer(data)

	cmd := exec.Command("convert", "-", destfilename)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}

	err = cmd.Start()
	if err != nil {
		return err
	}
	_, err = io.Copy(stdin, data_buf)
	if err != nil {
		return err
	}
	stdin.Close()
	err = cmd.Wait()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	data, err := ioutil.ReadFile("source.gif")
	if err != nil {
		log.Fatal(err)
	}
	err = runImagemagick(data, filepath.Join("/tmp", "abc", "dest.png"))
	if err != nil {
		log.Fatal(err)
	}
}

现在的问题是目录/tmp/abc/不存在。通常convert会给我这个结果:

$ convert - /tmp/abc/foo.png < source.gif 
convert: unable to open image `/tmp/abc/foo.png': No such file or directory @ error/blob.c/OpenBlob/2617.
convert: WriteBlob Failed `/tmp/abc/foo.png' @ error/png.c/MagickPNGErrorHandler/1755.

但是我在我的小程序中没有“看到”这个错误消息。我该如何获取错误消息并将其显示给用户?

(另一个子问题是:如果这段代码看起来还可以吗?有没有明显的缺陷?)

英文:

I call imagemagick's convert command with some data I have in memory (from html form upload/web server). This works fine, but I'd like to get the error output of convert in case of an error. How can I do that?

This is my code:

package main

import (
	&quot;bytes&quot;
	&quot;io&quot;
	&quot;io/ioutil&quot;
	&quot;log&quot;
	&quot;os/exec&quot;
	&quot;path/filepath&quot;
)

func runImagemagick(data []byte, destfilename string) error {
	data_buf := bytes.NewBuffer(data)

	cmd := exec.Command(&quot;convert&quot;, &quot;-&quot;, destfilename)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}

	err = cmd.Start()
	if err != nil {
		return err
	}
	_, err = io.Copy(stdin, data_buf)
	if err != nil {
		return err
	}
	stdin.Close()
	err = cmd.Wait()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	data, err := ioutil.ReadFile(&quot;source.gif&quot;)
	if err != nil {
		log.Fatal(err)
	}
	err = runImagemagick(data, filepath.Join(&quot;/tmp&quot;, &quot;abc&quot;, &quot;dest.png&quot;))
	if err != nil {
		log.Fatal(err)
	}
}

Now the artificial problem is that the directory /tmp/abc/ does not exist. Normally convert would give me this result:

$ convert - /tmp/abc/foo.png &lt; source.gif 
convert: unable to open image `/tmp/abc/foo.png&#39;: No such file or directory @ error/blob.c/OpenBlob/2617.
convert: WriteBlob Failed `/tmp/abc/foo.png&#39; @ error/png.c/MagickPNGErrorHandler/1755.

but I don't "see" this error message within my small program. How can I get the error message and show it to my user?

(And another sub-question is: can you give me an advice if this code looks OK? Are there any obvious flaws in it?)

答案1

得分: 1

Pipe stdout and stderr too. For example,

package main

import (
	&quot;bytes&quot;
	&quot;io&quot;
	&quot;io/ioutil&quot;
	&quot;log&quot;
	&quot;os/exec&quot;
	&quot;path/filepath&quot;
)

func runImagemagick(data []byte, destfilename string) error {
	cmd := exec.Command(&quot;convert&quot;, &quot;-&quot;, destfilename)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	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
	}
	_, err = io.Copy(stdin, bytes.NewBuffer(data))
	if err != nil {
		return err
	}
	stdin.Close()
	outData, err := ioutil.ReadAll(stdout)
	if err != nil {
		return err
	}
	if len(outData) &gt; 0 {
		log.Print(string(outData))
	}
	errData, err := ioutil.ReadAll(stderr)
	if err != nil {
		return err
	}
	if len(errData) &gt; 0 {
		log.Print(string(errData))
	}
	err = cmd.Wait()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	data, err := ioutil.ReadFile(&quot;source.gif&quot;)
	if err != nil {
		log.Fatal(err)
	}
	err = runImagemagick(data, filepath.Join(&quot;/tmp&quot;, &quot;abc&quot;, &quot;dest.png&quot;))
	if err != nil {
		log.Fatal(err)
	}
}

Output:

2013/03/03 15:02:20 convert.im6: unable to open image `/tmp/abc/dest-0.png&#39;: No such file or directory @ error/blob.c/OpenBlob/2638.
convert.im6: WriteBlob Failed `/tmp/abc/dest-0.png&#39; @ error/png.c/MagickPNGErrorHandler/1728.
2013/03/03 15:02:20 exit status 1
exit status 1
英文:

Pipe stdout and stderr too. For example,

package main

import (
	&quot;bytes&quot;
	&quot;io&quot;
	&quot;io/ioutil&quot;
	&quot;log&quot;
	&quot;os/exec&quot;
	&quot;path/filepath&quot;
)

func runImagemagick(data []byte, destfilename string) error {
	cmd := exec.Command(&quot;convert&quot;, &quot;-&quot;, destfilename)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	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
	}
	_, err = io.Copy(stdin, bytes.NewBuffer(data))
	if err != nil {
		return err
	}
	stdin.Close()
	outData, err := ioutil.ReadAll(stdout)
	if err != nil {
		return err
	}
	if len(outData) &gt; 0 {
		log.Print(string(outData))
	}
	errData, err := ioutil.ReadAll(stderr)
	if err != nil {
		return err
	}
	if len(errData) &gt; 0 {
		log.Print(string(errData))
	}
	err = cmd.Wait()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	data, err := ioutil.ReadFile(&quot;source.gif&quot;)
	if err != nil {
		log.Fatal(err)
	}
	err = runImagemagick(data, filepath.Join(&quot;/tmp&quot;, &quot;abc&quot;, &quot;dest.png&quot;))
	if err != nil {
		log.Fatal(err)
	}
}

Output:

2013/03/03 15:02:20 convert.im6: unable to open image `/tmp/abc/dest-0.png&#39;: No such file or directory @ error/blob.c/OpenBlob/2638.
convert.im6: WriteBlob Failed `/tmp/abc/dest-0.png&#39; @ error/png.c/MagickPNGErrorHandler/1728.
2013/03/03 15:02:20 exit status 1
exit status 1

答案2

得分: 1

不需要使用管道,因为bytes.Buffer实现了io.Writer接口,所以可以很好地用于收集程序的输出:

func runImagemagick(data []byte, destfilename string) error {     
    cmd := exec.Command("convert", "-", destfilename)
    
    var stdout, stderr bytes.Buffer
    cmd.Stdout = &stdout
    cmd.Stderr = &stderr
    
    err := cmd.Run()
    if err != nil {
        if ee, ok := err.(*exec.ExitError); ok {
            return &imagemagickError{ee, stdout.Bytes(), stderr.Bytes()}
        } else {
            return err
        }
    }
    
    if stderr.Len() > 0 {
        return errors.New(fmt.Sprintf("imagemagick wrote to stderr: %s", stderr.Bytes()))
    }
    
    if stdout.Len() > 0 {
        log.Print(stdout.Bytes())
    }
    return nil
 }
英文:

There's no need to use pipes because bytes.Buffer implements the io.Writer interface and so it can be used just fine to collect the program's output:

func runImagemagick(data []byte, destfilename string) error {     
    cmd := exec.Command(&quot;convert&quot;, &quot;-&quot;, destfilename)
    
    var stdout, stderr bytes.Buffer
    cmd.Stdout = &amp;stdout
    cmd.Stderr = &amp;stderr
    
    err := cmd.Run()
    if err != nil {
        if ee, ok := err.(*exec.ExitError); ok {
            return &amp;imagemagickError{ee, stdout.Bytes(), stderr.Bytes()}
        } else {
            return err
        }
    }
    
    if stderr.Len() &gt; 0 {
        return errors.New(fmt.Sprintf(&quot;imagemagick wrote to stderr: %s&quot;, stderr.Bytes()))
    }
    
    if stdout.Len() &gt; 0 {
        log.Print(stdout.Bytes())
    }
    return nil
 }

huangapple
  • 本文由 发表于 2013年3月4日 02:43:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/15189354.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定