Пакет flag в Go: работа с позиционными аргументами
Обычно команды принимают несколько аргументов, которые выступают в качестве субъекта фокуса команды. Например, команда head, которая распечатывает первые строки файла, часто вызывается как head example.txt. Файл example.txt представляет собой позиционный аргумент вызова команды head.
Функция Parse() продолжает выполнять синтаксическую проверку появляющихся флагов, пока не обнаружит аргумент, не являющийся флагом. Пакет flag делает их доступными через функции Args() и Arg().
В качестве иллюстрации построим упрощенную реализацию команды head, отображающей первые несколько строк указанного файла.
Создай новый файл head.go и добавь следующий код.
Вначале мы определяем переменную count, где будет храниться количество строк, которое программа должна считывать из файла. Мы определяем флаг -n, используя flag.IntVar, что отражает поведение первоначальной программы head. Эта функция позволяет нам передать собственный указатель в переменную в отличие от функций flag, у которых нет суффикса Var. Помимо этой разницы остальные параметры flag.IntVar соответствуют параметрам flag.Int: имя флага, значение по умолчанию и описание. Как и в предыдущем примере, мы вызовем flag.Parse() для обработки пользовательских данных.
Следующий раздел выполняет чтение файла. Мы определим переменную io.Reader, для которой будет задан запрошенный пользователем файл или которой будут передаваться стандартные входные данные программы. В выражении if мы используем функцию flag.Arg для доступа к первому аргументу после всех флагов. Если пользователь указал имя файла, оно будет задано. В противном случае это будет пустая строка (""). Если имя файла есть в наличии, мы используем функцию os.Open для открытия файла и задаем предварительно определенный для этого файла io.Reader. В противном случае мы используем os.Stdin для считывания стандартных исходных данных.
В заключительном разделе используется *bufio.Scanner, созданный с помощью bufio.NewScanner, для считывания строк из переменной io.Reader in. Мы проводим итерацию до значения count в цикле for и вызываем break, если при сканировании строчки buf.Scan получается значение false, показывающее, что количество строчек меньше, чем запрошенное пользователем.
Запусти эту программу и выведи содержимое записанного файла, используя head.go в качестве аргумента файла.
Разделитель -- представляет собой специальный флаг, который распознается пакетом flag и показывает, что за ним не идут другие аргументы флагов. При запуске этой команды выводится следующее.
Используй определенный тобой флаг -n для изменения объема выводимых данных.
Так выводится только выражение пакета.
Наконец, если программа определяет отсутствие аргументов позиции, она считывает исходные данные из стандартного источника, как и команда head. Попробуй запустить следующую команду.
Результат должен выглядеть так.
Поведение функций flag, которое мы наблюдали, ограничено исследованием вызова всей команды. Такое поведение требуется не всегда, особенно если ты пишешь инструмент командной строки, поддерживающий субкоманданте.