Last updated: 2025-04-01 18:36

You might not need Cobra

beyondcodebootcamp.github.io/presos/go-flag/

Go Flag, and Flags

https://pkg.go.dev/flag

AJ ONeal

@_beyondcode
twitch.tv/coolaj86
github.com/therootcompany


Deep-Learner

Dangerous Wrong Thinker

Gun for Hire


🐹 Go 📦 Node 🦎 Zig

🛜 Net 🔐 Sec 🐧 Proxmox


aj@therootcompany.com

Utah Colo on Meetup

https://www.meetup.com/utah-colo/

-flag
--flag   // double dashes are also permitted
-flag=x
-flag x  // non-boolean flags only

A Long Time Ago

In a Shell, Far, Far Away...

POSIX

  1. Strings
  2. Flags
  3. Options (GNU)
  4. Arguments

https://gist.github.com/coolaj86/1759b70e72f038869b7bf87816d9dc2e

1. POSIX Strings

expression
'string literal'
"string expression"

Whitespace-delimited

echo foo bar baz
echo   foo   bar   baz
echo '   foo   bar   baz   '

String Literals

Same as Go's ` string literals:

  • absolutely literal
  • NO escapes

String Literals

echo '$foo \'
echo 'bar
      baz'

String Expressions

Handle escape sequences, and $, $(...), ${...} expressions.

String Expressions

echo "$foo"
echo "Filename: $(date '+%F_%H.%M.%S')"

String Expr vs Expr

echo "$(echo '   foo   bar   baz   ')"
echo $(echo '   foo   bar   baz   ')

Expressions

All of the goodies of string expressions, plus...

echo
echo $PATH
echo (echo "Hello, World!")
{
    printf 'Hello, '
    echo 'World!'
} > greeting.txt
cmd_curl="$(echo "curl -fsSL")"
$cmd_curl 'https://example.com'
"$cmd_curl" 'https://example.com'

Pop Quiz!

echo string' # not a comment
       string literal # also not a comment
                     \'\'"string expression
                                        \""\\# word # comment

🫣 Answer

string # not a comment
       string literal # also not a comment
                     \'string expression
                                        "\# word

Bonus: Args All the Way Down

'echo' 'foo' 'bar' 'baz'

Note: this is a property of the shell

2. POSIX Flags

Flags are all arguments that:

  • begin with '-'
  • until the first argument that doesn't begin with '-'
  • or '--'
-flag1
-flag1 --flag2
-flag1 --flag2 arg1
-flag1 --flag2 arg1 -arg2
-flag1 --flag2 -- -arg1

Escaping Flags

touch 'foo' -rf
rm -- -rf

2. GNU Opts

Options are arguments to a flag

foo --bar ./baz

foo --bar=./baz

Be wary...

foo --bar ~/baz

foo --bar=~/baz

3. Arguments, again

The first argument after --, or not preceded by an option flag.

tar -cf ./etc.tar /etc

Go Flag

import (
    "flag"
)

func main() {
    name := flag.String("name", "", "the user's real name")
    flag.Parse()

    // ...
}

Rule #1: There are no Rules

import (
    "os"
)

func main() {
    if len(os.Args) > 1 {
        switch os.Args[1] {
            case "-V", "--version", "version":
                printVersion()
                return
        }
    }

    // ...
}

Rule #2: Avoid pointers

func main() {
    var verbose bool
    var email string

    flag.BoolVar(&verbose, "verbose", false, "show lots of detail")
    flag.StringVar(&email, "email", "", "show lots of detail")
}

Rule #3: Create an instance

func main() {
    var verbose bool

	mainFlags := flag.NewFlagSet("", flag.ContinueOnError)
    mainFlags.BoolVar(&verbose, "verbose", false, "show lots of detail")

    if err := mainFlags.Parse(); err != nil {
        fmt.Println(err)

        mainFlags.Usage()
        os.Exit(1)
        return
    }

    // ...
}

How to know a flag was set

func isFlagSet(name string) bool {
    found := false

    flag.Visit(func(f *flag.Flag) {
        if f.Name == name {
            found = true
        }
    })
    return found
}

END

Q&A