Re command line vs scripts, I am not convinced that the mental overhead of knowing two names for each flag and flipping back and forth when you context switch between the command line and a shell script really makes that much sense. Certainly common flags should be short and less common flags need not be, but personally I'd rather have one way to spell each. Certainly having just one name per flag is more in keeping with Go trying to keep things simple.
My officemate is a long-time Git user but was surprised the other day to see me type "git pull -r". He didn't know that -r was short for --rebase, and in fact I didn't know that --rebase was long for -r. This kind of mutual incomprehensibility is a tiny variant of the observation that every C++ programmer uses only a small subset of C++, but the problem is that each programmer chooses a different subset. Not having two names for a flag can be a feature.
Re typing, I am also not convinced that the overhead of rm -r -f vs rm -rf is really that high. Of course, rm is a bad example: if you are implementing rm, you MUST use the Unix conventions and accept -rf. But for new commands not burned into decades-old muscle memory, it's not clear that it's needed.
I think there are multiple valid design decisions that could be made here, and we've tried to tilt the balance toward simplicity, but of course other balances could be struck, and maybe in other contexts it might make sense to strike a different one.
I tried to make sure it was possible that someone could write a package (say, flg) with the following API (and nothing else):
// Package flg implements a getopt-compatible command line flag parser.
package flg
// Parse parses the command-line flags defined in package flag.
// In contrast to flag.Parse, Parse imposes getopt semantics:
// - single letter flag names must be specified with a single dash: -x
// - longer names must be specified with a double dash: --long
// - the argument to a single-letter flag can follow it immediately:
// -xfoo means -x foo when -x takes an argument.
// - multiple short flags can be combined: -xyz means -x -y -z,
// when neither -x nor -y takes an argument.
// - name aliases can be introduced by calling Alias before Parse
func Parse()
// Alias records new as an alias for the flag named old.
// Typically old is a long name and new is a single-letter name or vice versa.
// For example, Alias("r", "recursive").
func Alias(new, old string)
I believe it is, although I haven't seen one. That would let programs still use package flag as the data definition, so that they can reuse any other "plug ins" for the package (like custom flag.Values) but still provide a getopt-style parser if desired.