go语言的魔幻旅行37-exec包

805 阅读5分钟

青山依然在,几度夕阳红

最近的天气,实在是变化无常,少了以往的笃定,多了些许往常少有的轻狂。

go语言的exec包

exec包主要涉及一些与命令相关的api,借助这个包的能力,我们可以实现许多的终端命令功能、脚本调用功能。

package main

/*********************************************************************/
/**************** golang中exec包相关API讲解 ****************************/
/********************************************************************/

/*
Variables
func LookPath(file string) (string, error)
type Cmd
func Command(name string, arg ...string) *Cmd
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd
func (c *Cmd) CombinedOutput() ([]byte, error)
func (c *Cmd) Output() ([]byte, error)
func (c *Cmd) Run() error
func (c *Cmd) Start() error
func (c *Cmd) StderrPipe() (io.ReadCloser, error)
func (c *Cmd) StdinPipe() (io.WriteCloser, error)
func (c *Cmd) StdoutPipe() (io.ReadCloser, error)
func (c *Cmd) String() string
func (c *Cmd) Wait() error
type Error
func (e *Error) Error() string
func (e *Error) Unwrap() error
type ExitError
func (e *ExitError) Error() string
*/

func main() {

	/**
	*LookPath在PATH环境变量命名的目录中搜索可执行文件(名为可执行文件)。如果文件包含斜杠,
	*则直接尝试,不查询PATH。结果可能是绝对路径或相对于当前目录的路径。
	*func LookPath(file string) (string, error)
	*/

	/*
	path, err := exec.LookPath("./exec_demo.go")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("path:", path)
	*/

	/**
	*命令返回Cmd结构以执行具有给定参数的命名程序
	*func Command(name string, arg ...string) *Cmd
	*/

	/*
	cmd := exec.Command("tr", "a-z", "A-Z")
	cmd.Stdin = strings.NewReader("some input")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("in all caps: %q\n", out.String())
	*/

	/**
	*CommandContext类似于Command,但包含上下文。如果上下文在命令本身完成之前完成,
	*则提供的上下文用于终止进程(通过调用os.Process.Kill)
	*func CommandContext(ctx context.Context, name string, arg ...string) *Cmd
	*/

	/*
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()

	if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
		// This will fail after 100 milliseconds. The 5 second sleep
		// will be interrupted.
	}
	*/

	/**
	*CombinedOutput运行命令并返回其组合的标准输出和标准错误。
	*func (c *Cmd) CombinedOutput() ([]byte, error)
	*/

	/*
	cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", stdoutStderr)
	*/

	/**
	*输出运行命令并返回其标准输出。返回的任何错误通常都是* ExitError类型。
	*如果c.Stderr为零,则Output填充ExitError.Stderr。
	*func (c *Cmd) Output() ([]byte, error)
	*/

	/*
	out, err := exec.Command("date").Output()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("The date is %s\n", out)
	*/

	/**
	*运行将启动指定的命令并等待其完成。如果命令运行,返回的错误为nil,复制stdin,
	*stdoutstderr时没有问题,并且退出状态为零。如果命令启动但未成功完成,则错
	*误的类型为* ExitError。对于其他情况,可能会返回其他错误类型。如果调用goroutine
	*已使用runtime.LockOSThread锁定了操作系统线程并修改了任何可继承的OS-level线程状态
	*(例如Linux或Plan 9名称空间),则新进程将继承调用者的线程状态。
	*func (c *Cmd) Run() error
	*/

	/*
	cmd := exec.Command("sleep", "1")
	log.Printf("Running command and waiting for it to finish...")
	err := cmd.Run()
	log.Printf("Command finished with error: %v", err)
	*/

	/**
	*启动将启动指定的命令,但不等待其完成。如果启动成功返回,则将设置c.Process字段。
	*一旦命令退出,Wait方法将返回退出代码并释放关联的资源。
	*func (c *Cmd) Start() error
	*/

	/*
	cmd := exec.Command("sleep", "5")
	err := cmd.Start()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Waiting for command to finish...")
	err = cmd.Wait()
	log.Printf("Command finished with error: %v", err)
	*/

	/**
	*当命令启动时,StderrPipe返回将连接到命令的标准错误的管道。
	*在看到命令退出后,Wait将关闭管道,因此大多数调用者不需要自
	*己关闭管道。因此,在管道中的所有读取完成之前调用Wait是不正
	*确的。出于相同的原因,使用StderrPipe时使用“运行”是不正确的。
	*func (c *Cmd) StderrPipe() (io.ReadCloser, error)
	*/

	/*
	cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}

	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}

	slurp, _ := io.ReadAll(stderr)
	fmt.Printf("%s\n", slurp)

	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
	*/

	/**
	*当命令启动时,StdinPipe返回将连接到命令标准输入的管道。
	*在Wait看到命令退出后,管道将自动关闭。调用者只需要致电
	*Close即可强制管道尽快关闭。例如,如果在关闭标准输入之
	*前不会退出正在运行的命令,则调用者必须关闭管道。
	*func (c *Cmd) StdinPipe() (io.WriteCloser, error)
	*/

	/*
	cmd := exec.Command("cat")
	stdin, err := cmd.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		defer stdin.Close()
		io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
	}()

	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", out)
	*/

	/**
	*StdoutPipe返回一个管道,该管道将在命令启动时连接到命令的标准输出。在看到命令退出后,
	*Wait将关闭管道,因此大多数调用者不需要自己关闭管道。因此,在管道中的所有读取完成之前
	*调用Wait是不正确的。出于相同的原因,使用StdoutPipe时调用Run是不正确的。
	*func (c *Cmd) StdoutPipe() (io.ReadCloser, error)
	*/

	/*
	cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	var person struct {
		Name string
		Age  int
	}
	if err := json.NewDecoder(stdout).Decode(&person); err != nil {
		log.Fatal(err)
	}
	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s is %d years old\n", person.Name, person.Age)
	*/

	/**
	*Error类型记录执行失败的程序名和失败的原因。
	*func (c *Cmd) String() string
	*/

	/*
	cmd := exec.Command("tr", "a-z", "A-Z")
	cmd.Stdin = strings.NewReader("some input")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("in all caps: %q\n", out.String())
	*/

	/**
	*Wait会阻塞直到该命令执行完成,该命令必须是被Start方法开始执行的,如果命令成功执行,
	*stdinstdoutstderr的转交没有问题,并且返回状态码为0,方法的返回值为nil;
	*如果命令没有执行或者执行失败,会返回*ExitError类型的错误;否则返回的error可能是
	*表示I/O问题。Wait方法会在命令返回后释放相关的资源。
	*func (c *Cmd) Wait() error
	*/

	/*
	cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}

	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}

	slurp, _ := io.ReadAll(stderr)
	fmt.Printf("%s\n", slurp)

	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
	*/


	/*********************************************************************/
	/**************** golangexec包 Error结构体API讲解 ********************/
	/********************************************************************/

	/**
	*Error类型记录执行失败的程序名和失败的原因。
	*func (e *Error) Error() string
	*/



	/**
	*
	*func (e *Error) Unwrap() error
	*/

	/*********************************************************************/
	/**************** golangexec包ExitError结构体API讲解 *****************/
	/********************************************************************/

	/**
	*ExitError报告某个命令的一次未成功的返回。
	*func (e *ExitError) Error() string
	*/
}

小结

由于exec包的内容相对较少,掌握起来难度应该不是很大,在此不在赘述。