{"id":13410364,"url":"https://github.com/posener/cmd","last_synced_at":"2025-04-30T14:43:11.176Z","repository":{"id":57502227,"uuid":"218171249","full_name":"posener/cmd","owner":"posener","description":"The standard library flag package with its missing features","archived":false,"fork":false,"pushed_at":"2020-09-27T14:26:26.000Z","size":78,"stargazers_count":42,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-25T08:41:15.102Z","etag":null,"topics":["cmd","command","flag","go","golang","sub-command","subcommands"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/posener.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-29T00:32:11.000Z","updated_at":"2025-01-15T01:40:06.000Z","dependencies_parsed_at":"2022-09-13T07:02:05.621Z","dependency_job_id":null,"html_url":"https://github.com/posener/cmd","commit_stats":null,"previous_names":["posener/subcmd"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fcmd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fcmd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fcmd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fcmd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/posener","download_url":"https://codeload.github.com/posener/cmd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242667466,"owners_count":20166296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cmd","command","flag","go","golang","sub-command","subcommands"],"created_at":"2024-07-30T20:01:06.456Z","updated_at":"2025-03-09T08:30:48.474Z","avatar_url":"https://github.com/posener.png","language":"Go","readme":"# cmd\n\n[![codecov](https://codecov.io/gh/posener/cmd/branch/master/graph/badge.svg)](https://codecov.io/gh/posener/cmd)\n[![GoDoc](https://img.shields.io/badge/pkg.go.dev-doc-blue)](http://pkg.go.dev/github.com/posener/cmd)\n\nPackage cmd is a minimalistic library that enables easy sub commands with the standard `flag` library.\n\nThis library extends the standard library `flag` package to support sub commands and more\nfeatures in a minimalistic and idiomatic API.\n\nFeatures:\n\n- [x] Sub commands.\n\n- [x] Automatic bash completion.\n\n- [x] Flag values definition and check.\n\n- [x] Explicit positional arguments definition.\n\n- [x] Automatic usage text.\n\n## Usage\n\nDefine a root command object using the `New` function.\nThis object exposes the standard library's `flag.FlagSet` API, which enables adding flags in the\nstandard way.\nAdditionally, this object exposes the `SubCommand` method, which returns another command object.\nThis objects also exposing the same API, enabling definition of flags and nested sub commands.\nThe root object then have to be called with the `Parse` method, similarly to\nthe `flag.Parse` call.\n\n## Principles\n\n* Minimalistic and `flag`-like.\n\n* Any flag that is defined in the base command will be reflected in all of its sub commands.\n\n* When user types the command, it starts from the command and sub commands, only then types the\nflags and then the positional arguments:\n\n```go\n[command] [sub commands...] [flags...] [positional args...]\n```\n\n* When a command defines positional arguments, all its sub commands has these positional\narguments and thus can't define their own positional arguments.\n\n* When flag configuration is wrong, the program will panic.\n\n## Examples\n\nDefinition and usage of sub commands and sub commands flags.\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/posener/cmd\"\n)\n\nvar (\n\t// Define root command with a single string flag. This object the familiar standard library\n\t// `*flag.FlagSet` API, so it can be used similarly.\n\troot  = cmd.New()\n\tflag0 = root.String(\"flag0\", \"\", \"root string flag\")\n\n\t// Define a sub command from the root command with a single string flag. The sub command object\n\t// also have the same API as the root command object.\n\tsub1  = root.SubCommand(\"sub1\", \"first sub command\")\n\tflag1 = sub1.String(\"flag1\", \"\", \"sub1 string flag\")\n\n\t// Define a second sub command from the root command with an int flag.\n\tsub2  = root.SubCommand(\"sub2\", \"second sub command\")\n\tflag2 = sub1.Int(\"flag2\", 0, \"sub2 int flag\")\n)\n\n// Definition and usage of sub commands and sub commands flags.\nfunc main() {\n\t// Parse command line arguments.\n\troot.ParseArgs(\"cmd\", \"sub1\", \"-flag1\", \"value\")\n\n\t// Check which sub command was choses by the user.\n\tswitch {\n\tcase sub1.Parsed():\n\t\tfmt.Printf(\"Called sub1 with flag: %s\", *flag1)\n\tcase sub2.Parsed():\n\t\tfmt.Printf(\"Called sub2 with flag: %d\", *flag2)\n\t}\n}\n\n```\n\n### Values\n\nAn example that shows how to use advanced configuration of flags and positional arguments using\nthe predict package.\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/posener/cmd\"\n\t\"github.com/posener/complete/v2/predict\"\n)\n\nfunc main() {\n\t// Should be defined in global `var`.\n\tvar (\n\t\troot = cmd.New()\n\t\t// Define a flag with valid values 'foo' and 'bar', and enforce the values by `OptCheck()`.\n\t\t// The defined values will be used for bash completion, and since the OptCheck was set, the\n\t\t// flag value will be checked during the parse call.\n\t\tflag1 = root.String(\"flag1\", \"\", \"first flag\", predict.OptValues(\"foo\", \"bar\"), predict.OptCheck())\n\t\t// Define a flag to accept a valid Go file path. Choose to enforce the valid path using the\n\t\t// `OptCheck` function. The file name will also be completed in the bash completion\n\t\t// processes.\n\t\tfile = root.String(\"file\", \"\", \"file path\", predict.OptPredictor(predict.Files(\"*.go\")), predict.OptCheck())\n\t\t// Positional arguments should be explicitly defined. Define positional arguments with valid\n\t\t// values of 'baz' and 'buzz', and choose not to enforce these values by not calling\n\t\t// `OptCheck`. These values will also be completed in the bash completion process.\n\t\targs = root.Args(\"[args...]\", \"positional arguments\", predict.OptValues(\"baz\", \"buzz\"))\n\t)\n\n\t// Parse fake command line arguments.\n\troot.ParseArgs(\"cmd\", \"-flag1\", \"foo\", \"-file\", \"cmd.go\", \"buz\", \"bazz\")\n\n\t// Test:\n\n\tfmt.Println(*flag1, *file, *args)\n}\n\n```\n\n Output:\n\n```\nfoo cmd.go [buz bazz]\n```\n\n### Args\n\nIn the cmd package, positional arguments should be explicitly defined. They are defined using the\n`Args` or `ArgsVar` methods.\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/posener/cmd\"\n)\n\nfunc main() {\n\t// Should be defined in global `var`.\n\tvar (\n\t\troot = cmd.New()\n\t\t// Positional arguments should be defined as any other flag.\n\t\targs = root.Args(\"[args...]\", \"positional arguments for command line\")\n\t)\n\n\t// Parse fake command line arguments.\n\troot.ParseArgs(\"cmd\", \"v1\", \"v2\", \"v3\")\n\n\t// Test:\n\n\tfmt.Println(*args)\n}\n\n```\n\n Output:\n\n```\n[v1 v2 v3]\n```\n\n### ArgsFn\n\nAn example of how to parse positional arguments using a custom function. It enables the advantage\nof using named variables such as `src` and `dst` as opposed to args[0] and args[1].\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/posener/cmd\"\n)\n\nfunc main() {\n\t// Should be defined in global `var`.\n\tvar (\n\t\troot = cmd.New()\n\t\t// Define variables that will hold the command line positional arguments.\n\t\tsrc, dst string\n\t)\n\n\t// Define an `ArgsFn` that converts a list of positional arguments to the named variables. It\n\t// should return an error when the arguments are invalid.\n\targsFn := cmd.ArgsFn(func(args []string) error {\n\t\tif len(args) != 2 {\n\t\t\treturn fmt.Errorf(\"expected src and dst, got %d arguments\", len(args))\n\t\t}\n\t\tsrc, dst = args[0], args[1]\n\t\treturn nil\n\t})\n\n\t// Should be in `init()`.\n\t// Register the function in the root command using the `ArgsVar` method.\n\troot.ArgsVar(argsFn, \"[src] [dst]\", \"positional arguments for command line\")\n\n\t// Should be in `main()`.\n\troot.ParseArgs(\"cmd\", \"from.txt\", \"to.txt\")\n\n\t// Test:\n\n\tfmt.Println(src, dst)\n}\n\n```\n\n Output:\n\n```\nfrom.txt to.txt\n```\n\n### ArgsInt\n\nAn example of defining int positional arguments.\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/posener/cmd\"\n)\n\nfunc main() {\n\t// Should be defined in global `var`.\n\tvar (\n\t\troot = cmd.New()\n\t\t// Define a variable that will hold the positional arguments values. Use the `ArgsInt` type\n\t\t// to parse them as int.\n\t\targs cmd.ArgsInt\n\t)\n\n\t// Should be in `init()`.\n\t// Register the positional argument variable in the root command using the `ArgsVar` method.\n\troot.ArgsVar(\u0026args, \"[int...]\", \"numbers to sum\")\n\n\t// Should be in `main()`.\n\t// Parse fake command line arguments.\n\troot.ParseArgs(\"cmd\", \"10\", \"20\", \"30\")\n\n\t// Test:\n\n\tsum := 0\n\tfor _, n := range args {\n\t\tsum += n\n\t}\n\tfmt.Println(sum)\n}\n\n```\n\n Output:\n\n```\n60\n```\n\n### ArgsN\n\nAn example of defining an exact number of positional arguments.\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/posener/cmd\"\n)\n\nfunc main() {\n\t// Should be defined in global `var`.\n\tvar (\n\t\troot = cmd.New()\n\t\t// Define a variable that will hold positional arguments. Create the `ArgsStr` object with\n\t\t// cap=2 to ensure that the number of arguments is exactly 2.\n\t\targs = make(cmd.ArgsStr, 2)\n\t)\n\n\t// Should be in `init()`.\n\t// Register the positional argument variable in the root command using the `ArgsVar` method\n\t// (similar to the Var methods of the standard library).\n\troot.ArgsVar(\u0026args, \"[src] [dst]\", \"positional arguments for command line\")\n\n\t// Should be in `main()`.\n\t// Parse fake command line arguments.\n\troot.ParseArgs(\"cmd\", \"from.txt\", \"to.txt\")\n\n\t// Test:\n\n\tfmt.Println(args)\n}\n\n```\n\n Output:\n\n```\n[from.txt to.txt]\n```\n\n---\nReadme created from Go doc with [goreadme](https://github.com/posener/goreadme)\n","funding_links":[],"categories":["命令行","Command Line","Build Automation","命令行工具","命令行工具### 标准 CLI`用于创建一个标准命令行应用程序的库`"],"sub_categories":["标准CLI","Standard CLI","标准 CLI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposener%2Fcmd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fposener%2Fcmd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposener%2Fcmd/lists"}