Executing System Commands With Golang
Last Updated - 6th December, 2018
In this tutorial, we are going to be taking a look at the os/exec
package in
the standard library and how we can use this to successfully execute system
commands within our Go applications.
Note - The official documentation for executing system commands can be found under the exec package: os/exec package.
Prerequisites
- You will need Go version 1.11+ installed on your development machine.
Cross Compatibility Issues
Please note that some of these commands may not work on your operating system. If you are trying to write code that is compatible on multiple platforms then it would be wise to select commands that only feature on all platforms. If this is un-achievable then I recommend you add conditional logic to your program that executes a different system command depending on the system it’s executing on top of.
Checking Current Operating System
In order to check what operating system our code is running on we can use the runtime package and check the GOOS constant. This will return the operating system target:
if runtime.GOOS == "windows" {
fmt.Println("Can't Execute this on a windows machine")
} else {
execute()
}
Note - The full list of GOOS variables can be found here: Sys Package.
Implementation
Note - I’m writing this tutorial on MacOS using commands that may not necessarily work on Windows machines.
Let’s have a look at how we can start executing some really simple commands such
as ls
and pwd
using the os/exec
package, and once we have the basics
covered, we can move on to more advanced examples.
We’ll first of all need to import the 3 key packages for this example, the
fmt
, os/exec
and the runtime
package.
Once, we’ve done this, we’ll define an execute()
function which will attempt
to execute the
package main
import (
"fmt"
"os/exec"
"runtime"
)
func execute() {
// here we perform the pwd command.
// we can store the output of this in our out variable
// and catch any errors in err
out, err := exec.Command("ls").Output()
// if there is an error with our execution
// handle it here
if err != nil {
fmt.Printf("%s", err)
}
// as the out variable defined above is of type []byte we need to convert
// this to a string or else we will see garbage printed out in our console
// this is how we convert it to a string
fmt.Println("Command Successfully Executed")
output := string(out[:])
fmt.Println(output)
// let's try the pwd command herer
out, err = exec.Command("pwd").Output()
if err != nil {
fmt.Printf("%s", err)
}
fmt.Println("Command Successfully Executed")
output = string(out[:])
fmt.Println(output)
}
func main() {
if runtime.GOOS == "windows" {
fmt.Println("Can't Execute this on a windows machine")
} else {
execute()
}
}
If we then attempt to run this, we should see the following:
$ go run main.go
Command Successfully Executed ## ls command
main.go
Command Successfully Executed ## pwd command
/Users/elliot/Documents/Projects/elliotforbes/...
As you can see, both of the commands are successfully executed and we’ve managed to capture the output from these commands and subsequently output them within the context of our own Go program.
Passing in Arguments
Awesome, we’ve managed to get some really simple commands running, but how do we go about passing in arguments to these commands?
For instance, say I wanted to do an ls -ltr
as opposed to just a standard
ls
?
Thankfully, this is relatively easy, we just have to add these arguments to
.Command()
like so:
package main
import (
"fmt"
"os/exec"
"runtime"
)
func execute() {
out, err := exec.Command("ls", "-ltr").Output()
if err != nil {
fmt.Printf("%s", err)
}
fmt.Println("Command Successfully Executed")
output := string(out[:])
fmt.Println(output)
}
func main() {
if runtime.GOOS == "windows" {
fmt.Println("Can't Execute this on a windows machine")
} else {
execute()
}
}
When we go to execute this again, we should see the output now successfully
picking up our -ltr
flags:
$ go run main.go
Command Successfully Executed
total 8
-rw-r--r-- 1 elliot staff 988 6 Dec 17:52 main.go
Note -
.Command()
is an example of a Variadic Function which takes in any number of trailing arguments, therefore, you can pass in as many arguments to your initial command as you desire.
Conclusion
So, in this tutorial, we looked at how we could leverage the os/exec
package
in Go to execute system commands within our Go programs.
If you found this tutorial useful or wish to ask anything extra then please feel free to do so in the comments section below!
Note - If you want to keep up to date with the latest articles and updates on the site then please feel free to follow me on twitter: @Elliot_f