Go - Command Line Programs
Updated at 2016-08-18 21:13
This note contains information about creating programs that can be customized when launched from the command line and how to handle other command line related events.
You can get the raw command that was used to start the program with os.Args
.
package main
import (
"fmt"
"os"
)
func main() {
// Calling... main f1rst s3cond th1rd
arg := os.Args[3]
fmt.Println(arg) // => th1rd
argsWithProg := os.Args
fmt.Println(argsWithProg) // => [main f1rst s3cond th1rd]
argsWithoutProg := os.Args[1:]
fmt.Println(argsWithoutProg) // => [f1rst s3cond th1rd]
}
Flags are a common way to specify program parameters. For example, -a
in ls -a
is a flag.
package main
import (
"flag"
"fmt"
)
func main() {
// Flag name, default value, description.
// Description is show when the program is called with incorrect parameters.
swordPtr := flag.String("sword", "katana", "name of your sword of choice")
twkdPtr := flag.Bool("tweaked", false, "is the command tweaked")
warriorPtr := flag.Int("warriors", 1, "number of warriors you have")
// Assigning flag value to an existing variable.
var shield string
flag.StringVar(&shield, "shield", "buckler", "name of your shield")
flag.Parse() // After flags are declared, use flag.Parse().
// Calling...
// main -sword excalibur -tweaked -warriors 5 -shield "tower shield"
fmt.Println("sword:", *swordPtr) // sword: excalibur
fmt.Println("tweaked:", *twkdPtr) // tweaked: true
fmt.Println("warriors:", *warriorPtr) // warriors: 5
fmt.Println("shield:", shield) // shield: tower shield
}
os
package allows reading and writing environmental variables.
package main
import (
"fmt"
"os"
"strings"
)
func main() {
errSet := os.Setenv("MAN", "Roger Moore")
if errSet != nil {
panic(errSet)
}
manName := os.Getenv("MAN") // Roger Moore
womanName := os.Getenv("WOMAN") // Empty string
fmt.Println("MAN:", manName)
fmt.Println("WOMAN:", womanName)
// List all env variables.
for _, variable := range os.Environ() {
pair := strings.Split(variable, "=")
if pair[0] == "Path" {
fmt.Printf("%s=%s\n", pair[0], pair[1])
}
}
}
Define and parse flags in main
func. Read command line flags but fall back to env variables. Libraries should use constructor parameters or configuration object.
// (required1, required2, optionals)
foo, err := newFoo(*fooKey, fooConfig{
Bar: bar,
Period: 100 * time.Millisecond,
Output: nil,
})
if err != nil {
log.Fatal(err)
}
Signals are one way that operating systems communicate with running programs. Any non-trivial program should handle clean up after termination signals.
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
//signal.Notify(signalChan, syscall.SIGSTOP)
// `syscall` has around 30 error signals listed, only ones you cannot
// intercept are SIGKILL (immediate termination) and
// SIGSTOP (immediate pause for later resumption).
// Here are the most important ones.
// SIGINT = program should clean up files, sockets and processes (Ctrl+C).
// SIGTERM = basically the same as SIGINT.
// SIGQUIT = program should clean up only what is necessary, for debugging.
// SIGKILL = program is not allowed to clean up.
quitChannel := make(chan bool, 1)
go func() {
sig := <-signalChan
fmt.Println("received signal:", sig)
close(quitChannel)
}()
fmt.Println("waiting signal")
<-quitChannel
fmt.Println("exiting")
}