introduction
Command-line tools are rarely usable right away without additional configuration. Good defaults are important, but useful tools must accept user configuration. On most platforms, command-line utilities accept flags to customize how the command is executed. Flags are key-value separated strings appended after the command name. Go allows you to create command line tools that accept flags using theflag
package from the standard library.
In this tutorial you will learn different ways to use itflag
Package for building various types of command line tools. You use a flag to control program output, introduce positional arguments by mixing flags and other data, and then implement subcommands.
Using a flag to change the behavior of a program
Use offlag
The package consists of three steps: First,Define variablesNext, to collect flag values, define the flags your Go application will use and finally analyze the flags provided to the application when it runs. Most functions within theflag
The package is all about defining flags and binding them to variables you define. The parse phase is handled byparse()
Function.
To illustrate, create a program that displays aBoolean valueFlag that changes the printed message to standard output. if there is one-Colour
If you use the flag, the program will issue a blue message. If no flag is specified, the message will print colorless.
Create a new file namedboolean.go
:
- Nanoboolean.go
Add the following code to the file to create the program:
boolean.go
packagein the first placeimport ("Flag"„fmt“)TypColourstringconst (ColorBlack color= „\u001b[30m“Red colour= „\u001b[31m“color green= "\u001b[32m"color yellow= „\u001b33m“Color blue= \u001[34m]Farbreset= „\u001b[0m“)function colorize(color color,Newsstring) {fmt.print lines(string(Colour),News, string(Farbreset))}function in the first place() {use Color:=flag.Boos("Colour", INCORRECT, "Show colored output")flag.Analyzing()If *use Color{colorize(Color blue, "Hello, DigitalOcean!")return}fmt.print lines("Hello, DigitalOcean!")}
This example usesANSI escape sequencesto instruct the terminal to display colored output. Since these are special strings, it makes sense to define a new type for them. In this example, we called this typeColour
and defined the type as onestring
. Next, we define a color palette that is in theconst
block that follows. Thecolorize
Function defined afterconst
Block accepts one of theseColour
constants and onestring
Variable for the message to be colored. It then tells the terminal to change color by first printing the escape sequence for the requested color, then printing the message, and finally telling the terminal to reset the color by printing the special color reset sequence.
Insidein the first place
, we use thatflag.Bool
Function to define a boolean flag nameColour
. The second parameter of this function,INCORRECT
, sets the default value for this flag if not specified. Against your odds, you set this upWHERE
does not reverse the behavior, so if you specify a flag it will become false. Consequently, the value of this parameter is almost alwaysINCORRECT
with boolean flags.
The last parameter is a documentation string that can be printed as a usage report. The value returned by this function is a reference to abunch
. Offlag.Parse
The function on the next line uses this pointer to find thebunch
Variable based on the flags passed by the user. We can then check the valuebunch
Pointer by unreferencing the pointer. For more information about pointer variables, see thePointer Guide. With this boolean value we can then callcolorize
if that-Colour
flag is set and call thatfmt.Println
Variable if flag is absent.
Save the file and run the program without flags:
- Run boolean.go
You will see the following output:
Exit
Hello DigitalOcean!
Now run this program again with the-Colour
Flag:
- Run boolean.go-Colour
The output is the same text, but this time in blue.
Flags are not the only values passed to commands. You can also send file names or other data.
Working with positional arguments
Commands usually have a set of arguments that serve as the subject of the command's focus. For example theKopf
The command that prints the first few lines of a file is often called asKopf example.txt
. The fileexample.txt
is a positional argument when calling theKopf
Commando.
Ofparse()
The function continues to analyze flags it encounters until it encounters a non-flag argument. Theflag
The package makes these available through theArguments()
Inarg()
functions.
To demonstrate this, create a simplified redeployment ofKopf
Command that shows the first few lines of a specific file:
Create a new file namedhead.go
and add the following code:
head.go
packagein the first placeimport („bufio“"Flag"„fmt“"io"„os“)function in the first place() {Warto countintflag.IntVar(&to count, "N", 5, "Number of lines to read from file")flag.Analyzing()Warin me.ReaderIffilenames:=flag.Arg(0);filenames!= „“ {F,wrong:=os.Open(filenames)Ifwrong!= Nul {fmt.print lines("Error opening file: Error:",wrong)os.Exit(1)}DelayF.Close to()In=F} anders {In=os.Standard}buf:=bufio.Neuer scanner(In)forI:= 0;I<to count;I++ {If !buf.Scan() {pause}fmt.print lines(buf.Text())}Ifwrong:=buf.wrong();wrong!= Nul {fmt.Fprintln(os.Stderr, "Error reading: Error:",wrong)}}
First we define ato count
Variable containing the number of lines the program should read from the file. Then we define the-N
use flagflag.IntVar
, which mirrors the behavior of the originalKopf
Program. This function allows us to pass ourspointerto a variable as opposed toflag
Features that don'tWar
Suffix. Other than this difference, so are the rest of the parametersflag.IntVar
follow himvlag.Int
Match: The flag name, a default value, and a description. Just like in the previous example, we then make a callflag.Parse()
to process user input.
The next section reads the file. We define one firstio.Reader
Variable set to the file requested by the user or to standard input passed to the program. Within theIf
Explanation, we use thevlag.Arg
Function to access the first positional argument after all flags. If the user provided a file name, it will be set. Otherwise it's the empty string („“
). If a filename exists, we use itos.Open
Function to open this file and theio.Reader
We have defined this file before. Otherwise we useos.Stdin
reading standard input.
The last part uses a*bufio.Scanner
made withbufio.NewScanner
read lines fromio.Reader
VariableIn
. We iterate to the value ofto count
make use of onefor loop, to call to actionpause
if you scan the line withbuf.Scan
generates oneINCORRECT
Value indicating that the number of rows is less than the number requested by the user.
Run this program and view the contents of the file you just wrotehead.go
as an argument:
- ga rennen head.go -- head.go
Of--
Delimiter is a special flag recognized byflag
Packet indicating that no further flag arguments follow. When you run this command, you get the following output:
Exit
Package mainimport ("bufio" "vlag"
Use the-N
Flag you defined to adjust the output amount:
- ga rennen head.go-N 1head.go
This only displays the package statement:
Exit
(Video) Lisa Lisa & Cult Jam, Full Force - I Wonder If I Take You Home (Official Music Video)Play pack
Finally, when the program realizes that no positional arguments have been provided, it reads the standard input as followsKopf
. Try running this command:
- Echo "Vis\NHummer\NBind\NElritzen" |ga rennen head.go-N 3
You see the output:
Exit
Fish Cancer Sharks
The behavior offlag
The features you've seen so far are limited to examining the entire command call. You don't always want this behavior, especially if you're writing a command-line program that supports subcommands.
Use FlagSet to implement subcommands
Modern command line applications often implement "subcommands" to bundle a set of tools under one command. The most popular tool using this pattern isIdiot
. When researching a command such asgit begin
,Idiot
is the command andinside
is the sub-command ofIdiot
. A notable feature of subcommands is that each subcommand can have its own set of flags.
Go applications can support subcommands with their own set of flagsFlag.(*FlagSet)
Type. To demonstrate this, create a program that implements a command using two subcommands with different flags.
Create a new file namedsubcommando.go
and add the following content to the file:
packagein the first placeimport ("Wrong""Flag"„fmt“„os“)function NewGreetCommand() *GreetCommand{gc:= &GreetCommand{fs:flag.NewFlagSet("regards",flag.ContinueOnError),}gc.fs.StringVar(&gc.Name, "Name", "Welt", "Name of person to be greeted")returngc}TypGreetCommandStructure {fs*flag.FlagSet namestring}function (G*GreetCommand) Name() string {returnG.fs.Name()}function (G*GreetCommand) inside(arguments[]string) Wrong {returnG.fs.Analyzing(arguments)}function (G*GreetCommand) Loop() Wrong {fmt.print lines("Hallo",G.Name, „!“)return Nul}Typrunnerkoppel {inside([]string) WrongLoop() WrongName() string}function carrot(arguments[]string) Wrong {If to borrow(arguments) < 1 {returnWrong.New("You must pass a subcommand")}cmds:= []runner{NewGreetCommand(),}under command:=os.argument[1]for _,cmd:= Areacmds{Ifcmd.Name() ==under command{cmd.inside(os.argument[2:])returncmd.Loop()}}returnfmt.wrong("Unknown subcommand: %s",under command)}function in the first place() {Ifwrong:= carrot(os.argument[1:]);wrong!= Nul {fmt.print lines(wrong)os.Exit(1)}}
This program is divided into a number of parts: thein the first place
function thatcarrot
Function and the individual functions that implement the subcommand. Thein the first place
The function handles errors returned by commands. When a function returns aWrong, DieIf
The statement catches it, prints the error, and the program exits with the status code1
, indicating that the rest of the operating system has encountered an error. Insidein the first place
we pass all the arguments with which the program was calledcarrot
. We remove the first argument, the name of the program (in the previous examples)../subcommando
) by cuttingde.Args
First.
Ofcarrot
function defined[] Renner
, where all subcommands would be defined.runner
is akoppelfor subcommands that allow itcarrot
to get the name of the subcommandName()
and compare it with the contentunder command
Variable. After after iteration the correct subcommand is foundcmds
Variably, we initialize the subcommand with the remaining arguments and call the commandsLoop()
Method.
We only define one subcommand, although we could easily create more with this framework. TheGreetCommand
is instantiated withNewGreetCommand
where we create something new*flag.FlagSet
useflag.NewFlagSet
.flag.NewFlagSet
takes two arguments: a name for the set flag and a strategy for reporting parsing errors. The*flag.FlagSet
The name can be accessed through theflag.(*FlagSet).Name
Method. We use this in the(*GreetCommand).Name()
method to make the name of the subcommand match the name we gave it*flag.FlagSet
.NewGreetCommand
also defines one-Name
Mark in a similar way to the previous examples, but instead call this a method outside the*flag.FlagSet
area of*Greet Commando
,gc.fs
. Ifcarrot
calls theInside()
method of*Greet Commando
, we pass the specified arguments to theAnalyzing
method of*flag.FlagSet
veld.
Subcommands are easier to spot if you build and then run this program. Create the program:
- Go to create subcommand.go
Now run the program without arguments:
- ./subcommando
You see this output:
Exit
You must pass a subcommand
Now run the program with theregards
subcommand:
- ./salute subcommand
This produces the following output:
Exit
Hello World !
Now use the-Name
flag alongregards
To specify a name:
- ./salute subcommand-Name Sammy
You will see this output from the program:
Exit
(Video) Rich The Kid - Plug WalkHalloSammy!
This example illustrates some of the principles behind how to structure larger command-line applications in Go.Flag set
s are intended to give developers more control over where and how flags are processed by the flag parsing logic.
Diploma
Flags make your applications more useful in more contexts because they give your users control over how the programs run. It's important to give users convenient default settings, but you also need to give them the option to ignore settings that don't work for their situation. You saw thatflag
The package provides flexible ways to present configuration options to your users. You can choose a few simple flags or create an expandable set of sub-commands. In both cases, use theflag
The package helps you build tools in the style of the long history of flexible and scriptable command-line tools.
Check out our complete guide to learn more about the Go programming languageSeries "How to code in Go"..