SoFunction
Updated on 2025-03-05

golang encapsulates a command line function (return stderr/stdout/exitcode) sample code

Start the shell to execute the command line

In Go, you can useos/execThe package executes external commands without calling the shell, and can obtain the process's exit code, standard output and standard error output. Below is an encapsulated functionrunCommand, it meets your needs:

package main
import (
	"bytes"
	"fmt"
	"os/exec"
)
// The runCommand function accepts a command line string, executes it and returns the exit code, standard output and standard error outputfunc runCommand(cmdline string) (exitCode int, stdout string, stderr string, err error) {
	// parse the command line and prepare to execute	cmd := ("sh", "-c", cmdline)
	var outBuffer, errBuffer 
	 = &outBuffer
	 = &errBuffer
	// Execute the command	err = ()
	stdout = ()
	stderr = ()
	// Get the exit code.  If the command is executed error, try to get the exit code	if err != nil {
		if exitError, ok := err.(*); ok {
			exitCode = ()
		} else {
			// If a non-ExitError type error occurs, such as the execution file does not exist or there is no execution permission			return 0, stdout, stderr, err
		}
	} else {
		// The command is successfully executed, the exit code is 0		exitCode = 0
	}
	return exitCode, stdout, stderr, nil
}
func main() {
	// Test the runCommand function	exitCode, stdout, stderr, err := runCommand("ls -a")
	if err != nil {
		("Command execution error: %v\n", err)
	}
	("Exit code: %d\nStandard output: %s\nStandard error output: %s\n", exitCode, stdout, stderr)
}

HererunCommandThe function accepts a command line string, executes this command, and returns the relevant running result. This function usesto avoid calling shells. We pass the command toshof-cParameters, indirectly execute commands, but bypass the normal search mechanism of the executable file to prevent shell injection problems.

The result output will be written to, so you can read and convert it to a string. If there is an error, and the error is*Type, it means that the command returns a non-zero exit code. At this time, we can obtain and return this exit code; if it is an error of other types, it will directly return an error.

The return value of this function contains the process's exit code, the string representation of the standard output and standard error output, and a possible error value. If the command is executed successfully (even if its exit code is non-zero), the error value isnil. If a Go runtime error occurs in the function, such as the command does not exist or cannot be started, this error will be returned.

Way not to start the shell

Indeed, the previous example is calledshRun the command indirectly and the shell will still be started. To avoid this, we will directly decompose the command line string into command names and parameters, and then execute this command directly without the shell. The following are modifiedrunCommandfunction, it will useto parse incoming command line strings and will not start the shell.

package main
import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"
)
// The runCommand function accepts a command line string, executes it (no shell startup) and returns the exit code, standard output and standard error outputfunc runCommand(cmdline string) (exitCode int, stdout string, stderr string, err error) {
	// Use parse the command line to separate commands and parameters	args := (cmdline)
	if len(args) == 0 {
		return 0, "", "", ("no command provided")
	}
	cmdName := args[0]
	cmdArgs := args[1:]
	// Prepare to execute commands without shell	cmd := (cmdName, cmdArgs...)
	var outBuffer, errBuffer 
	 = &outBuffer
	 = &errBuffer
	// Execute the command	err = ()
	stdout = ()
	stderr = ()
	// Get the exit code.  If the command is executed error, try to get the exit code	if exitErr, ok := err.(*); ok {
		err = nil // Clean up error, we have obtained the exit code		exitCode = ()
	} else if err != nil {
		// If a non-ExitError type error occurs, such as the execution file does not exist or there is no execution permission		exitCode = -1
	} else {
		// The command is successfully executed, the exit code is 0		exitCode = 0
	}
	return exitCode, stdout, stderr, err
}
func main() {
	// Test the runCommand function	exitCode, stdout, stderr, err := runCommand("ls -a -l -h")
	if err != nil {
		("Command execution error: %v\n", err)
	}
	("Exit code: %d\nStandard output: %s\nStandard error output: %s\n", exitCode, stdout, stderr)
}

Note that this function assumes that the command line argument does not contain quotation-enclosed parameters or other elements that require shell parsing (such as wildcards)*Or redirect>). It simply takes the whitespace as a parameter separator, which is a limitation. If you need to parse complex command line strings (including quotes or special characters), then you need a more powerful parser, or you need to preprocess command line strings in some way.

Because the commands are executed directly without going through the shell, the features originally used in the shell (such as wildcard expansion, environment variable replacement, etc.) will no longer be available. It is safe to make sure that your command line string is passed directly to the system call. If you need the shell feature, you may also need to call the shell, but that's exactly what you want to avoid.

Expression err.(*) about type assertions

In Go,err.(*)is an expression of type assertion. Type assertions are used to check variableserrWhether it is a specific type, or can be converted to a specific type. In this case, type assertion checkerrCan it be asserted as*type.

yesos/execA structure type in the package, which implementserrorThe interface contains information about exit errors. When an external command run ends and returns a non-zero exit status,os/execPackedRunorWaitThe function will return aerrorThe value of type, which is usually a*An instance of type.

A type assertion usually has two forms:

  • x.(T): This form is used to assert variablesxIs it of typeT. If the assertion is successful, you will getxTypes ofTvalue. If it fails, a runtime error will be generated. Therefore, when using this form, it must be very certainxCan be asserted as typeT
  • x, ok := x.(T): This type of assertion form is safer because if the assertion fails, it will not throw an error, but willokThe value offalse,at the same timexThe value ofTzero value. If you're not surexIs the type ofTOr you should use this form when you want to safely check the type.

In the provided code example, we use the second form of type assertion:

if exitErr, ok := err.(*); ok {
    exitCode = ()
    // ...
}

Here, we try toerrorvalueerrAsserted as type*. If the assertion is successful (indicating that the external command failed to execute and a non-zero exit code is returned), the variableokThe value oftrueexitErrWill be*Type, we can pass itExitCode()Method gets the actual exit code. If the assertion fails (errno*Type), thenokforfalse, which usually meanserrIs another type of error ornil

This is the article about golang encapsulating a function that executes command line (return stderr/stdout/exitcode). This is all about golang encapsulating a function that executes command line. For more related golang, please search for my previous article or continue browsing the related articles below. I hope everyone will support me in the future!