Флаг в руки

Я считаю — это очень правильно, что в Go реализован свой стандартный парсер опций. Даже на первый взгляд он кажется намного удобнее классического getopt().
Так вот, часто в различного рода утилитах параметры командной строки передаются в виде «команда + опции»:

$ route add -net .....
$ VBoxManage convertfromraw --format ....
$ eselect news read --raw

Чтобы разбирать такие опции требуется вначале вычитать argv[1], и в зависимости от его значения распарсить идущие следом опции.
Проблема в том, что flag.Parse() работает с целым массивом os.Args, а нам надо бы из него удалить первый элемент (команду).
Заглянув в исходники flag.go, я увидел там функцию:

func ParseForTesting(args []string) (result bool)

Ей можно передавать произвольный слайс строк вместо аргументов. Но в комментариях очень убедительно сказано, что функция пригодна только для тестирования.
Стало быть, ищем другой выход. А он оказывается еще проще — надо подменить значение os.Args, так же как и в случае с getopt() сдвигали указатель на **argv.

Вот как можно обрабатывать команды:

package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	var n int
	var s string

	// Вычитываем команду
	cmd := os.Args[1]

	// Оставляем аргументы со первого и до конца
	// При этом первый (наша команда) считается именем приложения
	os.Args = os.Args[1:]

	// Указываем нужные опции в зависимости от команды
	switch cmd {
	case "num":
		flag.IntVar(&n, "n", 0, "Numeric value")
	case "str":
		flag.StringVar(&s, "s", "", "String value")
	}

	// Разбираем опции
	flag.Parse()

	fmt.Println("Cmd=", cmd, ", n=", n, ", s=", s)
}

Вот как это работает:

# Передаем строку
$ ./8.out str -s hello
Cmd= str , n= 0 , s= hello
# Передаем число
$ ./8.out num -n 9
Cmd= num , n= 9 , s=
# Передаем неправильный аргумент (строку вместо числа)
$ ./8.out num -s hello
flag provided but not defined: -s
Usage of num:
  -n=0: Numeric value
# Вызываем help для команд
$ ./8.out num -h
flag provided but not defined: -h
Usage of num:
  -n=0: Numeric value
$ ./8.out str -h
flag provided but not defined: -h
Usage of str:
  -s="": String value

Удобство флагов еще в том, что опции можно задавать из различных мест (лишь бы до вызова flag.Parse()). Скажем, если ваше приложение разделено на модули, то каждый модуль при инициализации может добавить необходимые ему опции. После вызова flag.Parse() каждый получит свои параметры, указанные в командной строке.

Вообщем, пробуйте! У go еще много интересных возможностей.

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s