Start the shell to execute the command line
In Go, you can useos/exec
The 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) }
HererunCommand
The 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 to
sh
of-c
Parameters, 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 calledsh
Run 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 modifiedrunCommand
function, 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 variableserr
Whether it is a specific type, or can be converted to a specific type. In this case, type assertion checkerr
Can it be asserted as*
type.
yes
os/exec
A structure type in the package, which implementserror
The interface contains information about exit errors. When an external command run ends and returns a non-zero exit status,os/exec
PackedRun
orWait
The function will return aerror
The 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 variables
x
Is it of typeT
. If the assertion is successful, you will getx
Types ofT
value. If it fails, a runtime error will be generated. Therefore, when using this form, it must be very certainx
Can 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 will
ok
The value offalse
,at the same timex
The value ofT
zero value. If you're not surex
Is the type ofT
Or 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 toerror
valueerr
Asserted as type*
. If the assertion is successful (indicating that the external command failed to execute and a non-zero exit code is returned), the variableok
The value oftrue
,exitErr
Will be*
Type, we can pass itExitCode()
Method gets the actual exit code. If the assertion fails (err
no*
Type), thenok
forfalse
, which usually meanserr
Is 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!