Могут ли флаги командной строки в Go быть обязательными?

Есть ли способ установить, что определенные флаги являются обязательными, или мне нужно проверить их присутствие самостоятельно?

Ответ 1

Пакет flag не поддерживает обязательные или обязательные флаги (это означает, что флаг должен быть указан явно).

Вы можете использовать разумные значения по умолчанию для (всех) флагов. И если флаг - это что-то вроде разумного значения по умолчанию, проверьте значение в начале вашего приложения и остановите сообщение об ошибке. В любом случае вы должны выполнить проверку значения флага (а не только для обязательных флагов), поэтому это не должно означать каких-либо (больших) накладных расходов, и это хорошая практика в целом.

Ответ 2

Мне нравится пакет github.com/jessevdk/go-flags для использования в CLI. Он предоставляет required атрибут, чтобы установить флаг обязательным. Как это:

var opts struct {
...
    // Example of a required flag
    Name string 'short:"n" long:"name" description:"A name" required:"true"'
...
}

Ответ 3

go-flags позволяют объявлять как обязательные флаги, так и необходимые позиционные аргументы:

var opts struct {
    Flag string 'short:"f" required:"true" name:"a flag"'
    Args struct {
        First   string 'positional-arg-name:"first arg"'
        Sencond string 'positional-arg-name:"second arg"'
    } 'positional-args:"true" required:"2"'
}
args, err := flags.Parse(&opts)

Ответ 4

Как уже упоминалось, пакет flag не предоставляет эту функцию напрямую, и обычно вы можете (и должны) быть в состоянии обеспечить разумное значение по умолчанию. Для случаев, когда вам нужно только небольшое количество явных аргументов (например, имя входного и выходного файлов), вы можете использовать позиционные аргументы (например, после flag.Parse() проверьте, что flag.NArg()==2 и затем flag.NArg()==2 input, output := flag.Arg(0), flag.Arg(1)).

Если, однако, у вас есть случай, когда это неразумно; скажем, несколько целых флагов, которые вы хотите принять в любом порядке, где любое целочисленное значение является разумным, но по умолчанию нет. Затем вы можете использовать функцию flag.Visit чтобы проверить, явно ли установлены флаги, которые вам flag.Visit или нет. Я думаю, что это единственный способ определить, был ли флаг явно установлен для него значением по умолчанию (не считая настраиваемого flag.Value Тип типа с реализацией Set который поддерживал состояние).

Например, возможно, что-то вроде:

    required := []string{"b", "s"}
    flag.Parse()

    seen := make(map[string]bool)
    flag.Visit(func(f *flag.Flag) { seen[f.Name] = true })
    for _, req := range required {
        if !seen[req] {
            // or possibly use 'log.Fatalf' instead of:
            fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
            os.Exit(2) // the same exit code flag.Parse uses
        }
    }

Playground

Это приведет к ошибке, если либо флаг "-b", либо "-s" не был явно установлен.

Ответ 5

Если у вас есть путь к флагом, просто проверьте, содержит ли * путь какое-то значение

var path = flag.String("f", "", "/path/to/access.log")
flag.Parse()
if *path == "" {
    usage()
    os.Exit(1)
}