The Go language calls Shell with the implementation of the executable

  • 2020-11-20 06:08:38
  • OfStack

The os/exec package can be used to invoke external commands, can pipe input and output, and supports blocking and non-blocking execution of commands.

The key type in the os/exec package is Cmd, and all of the methods described below serve this type:

func Command(name string, arg ...string) *Cmd
Method returns 1 *Cmd to execute the program specified by name (with the arg parameter)

func (c *Cmd) Run() error
Executes the command contained in Cmd and blocks until the command execution is complete

func (c *Cmd) Start() error
Execute the command contained in Cmd, and the method returns immediately without waiting for the command to complete execution

func (c *Cmd) Wait() error
This method blocks until the command in Cmd, which must have been started by the Start method, completes

func (c *Cmd) Output() ([]byte, error)
Execute the command contained in Cmd and return the standard output slice

func (c *Cmd) CombinedOutput() ([]byte, error)
Execute the command contained in Cmd and return a slice of standard output merged with standard error

func (c *Cmd) StdinPipe() (io.WriteCloser, error)
Returns a pipe that connects to its standard input after the command in Cmd is started

func (c *Cmd) StdoutPipe() (io.ReadCloser, error)
Returns a pipe that connects to its standard output after the command in Cmd is started

func (c *Cmd) StderrPipe() (io.ReadCloser, error)
Returns a pipe that connects to standard error after the command in Cmd is started

Examples of ordinary calls:

Call the Shell command or executable

Demo creates an empty file in the current directory


package main

import (
  "fmt"
  "os/exec"
)

func main(){
  cmd := exec.Command("touch", "test_file")

  err := cmd.Run()
  if err != nil {
    fmt.Println("Execute Command failed:" + err.Error())
    return
  }

  fmt.Println("Execute Command finished.")
}

1 It is generally not recommended to call the Shell script using this default mode:


cmd := exec.Command("my_shell.sh")

Because of the actual execution result and command line execution #sh ES84en_shell.sh1 in this way, if your Shell script does not meet the specification of sh, the call will fail.

Call the Shell script

Set bash to invoke the specified Shell script, dir_size.sh for the Shell script we tested. After the call is complete, print the standard output of the Shell script to the console.


package main

import (
  "fmt"
  "os/exec"
)

func main(){
  command := `./dir_size.sh .`
  cmd := exec.Command("/bin/bash", "-c", command)

  output, err := cmd.Output()
  if err != nil {
    fmt.Printf("Execute Shell:%s failed with error:%s", command, err.Error())
    return
  }
  fmt.Printf("Execute Shell:%s finished with output:\n%s", command, string(output))
}

dir_size.sh sample file contains the following contents to output the size of the current directory:


#!/bin/bash
du -h --max-depth=1 $1

Go program results:


[root@localhost opt]# ll
total 2120
-rwx------. 1 root root   36 Jan 22 16:37 dir_size.sh
-rwx------. 1 root root 2152467 Jan 22 16:39 execCommand
drwxrwxr-x. 11 1000 1000  4096 Jul 12 2017 kibana
drwx------. 2 root root  4096 Jan 16 10:45 sftpuser
drwx------. 3 root root  4096 Jan 22 16:41 upload
[root@localhost opt]# ./execCommand 
Execute Shell:./dir_size.sh . finished with output:
4.0K  ./sftpuser
181M  ./kibana
1.1G  ./upload
1.2G  .

Use I/O Pipe

Demonstrates the standard input of the grep command using a pipe to filter the string containing test, and the standard output using a pipe to print the run result:


package main

import (
  "fmt"
  "io/ioutil"
  "os/exec"
)

func main(){
  cmd := exec.Command("/bin/bash", "-c", "grep test")

  stdin, _ := cmd.StdinPipe()
  stdout, _ := cmd.StdoutPipe()

  if err := cmd.Start(); err != nil{
    fmt.Println("Execute failed when Start:" + err.Error())
    return
  }

  stdin.Write([]byte("go text for grep\n"))
  stdin.Write([]byte("go test text for grep\n"))
  stdin.Close()

  out_bytes, _ := ioutil.ReadAll(stdout)
  stdout.Close()

  if err := cmd.Wait(); err != nil {
    fmt.Println("Execute failed when Wait:" + err.Error())
    return
  }

  fmt.Println("Execute finished:" + string(out_bytes))
}

Go program results:

[

[root@localhost ~]# ./execCommand
Execute finished:go test text for grep

]

Blocking/non-blocking calls

The introduction to the method at the beginning of the article is very clear, and the previous examples are covered, so I will not explain it separately.

Reference document:
GoLang standard library documentation


Related articles: