{"id":13495882,"url":"https://github.com/ko1nksm/getoptions","last_synced_at":"2025-05-15T23:08:45.928Z","repository":{"id":38978944,"uuid":"286552947","full_name":"ko1nksm/getoptions","owner":"ko1nksm","description":"An elegant option/argument parser for shell scripts (full support for bash and all POSIX shells)","archived":false,"fork":false,"pushed_at":"2024-11-18T20:42:50.000Z","size":282,"stargazers_count":445,"open_issues_count":11,"forks_count":24,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-12T04:55:53.973Z","etag":null,"topics":["argparse","argument","bash","busybox","code-generator","dash","getopt","getopts","ksh","parsing","posix-compliant","shell-scripts","zsh"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ko1nksm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ko1nksm"}},"created_at":"2020-08-10T18:41:27.000Z","updated_at":"2025-05-02T09:37:43.000Z","dependencies_parsed_at":"2024-01-03T04:12:51.087Z","dependency_job_id":"89933f9d-06f0-4956-a09f-de8f70363b0e","html_url":"https://github.com/ko1nksm/getoptions","commit_stats":{"total_commits":293,"total_committers":6,"mean_commits":"48.833333333333336","dds":0.03412969283276446,"last_synced_commit":"139d121807db67f632b412b2a00ece851df73203"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ko1nksm%2Fgetoptions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ko1nksm%2Fgetoptions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ko1nksm%2Fgetoptions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ko1nksm%2Fgetoptions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ko1nksm","download_url":"https://codeload.github.com/ko1nksm/getoptions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436949,"owners_count":22070947,"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":["argparse","argument","bash","busybox","code-generator","dash","getopt","getopts","ksh","parsing","posix-compliant","shell-scripts","zsh"],"created_at":"2024-07-31T19:01:39.215Z","updated_at":"2025-05-15T23:08:40.674Z","avatar_url":"https://github.com/ko1nksm.png","language":"Shell","funding_links":["https://github.com/sponsors/ko1nksm"],"categories":["Shell","bash","Shell Script Development"],"sub_categories":["Directory Navigation"],"readme":"# getoptions \u003c!-- omit in toc --\u003e\n\n[![Test](https://github.com/ko1nksm/getoptions/workflows/Test/badge.svg)](https://github.com/ko1nksm/getoptions/actions)\n[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/ko1nksm/getoptions?logo=codefactor)](https://www.codefactor.io/repository/github/ko1nksm/getoptions)\n[![Codecov](https://img.shields.io/codecov/c/github/ko1nksm/getoptions?logo=codecov)](https://codecov.io/gh/ko1nksm/getoptions)\n[![kcov](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fko1nksm.github.io%2Fgetoptions%2Fcoverage.json\u0026query=percent_covered\u0026label=kcov\u0026suffix=%25)](https://ko1nksm.github.io/getoptions/)\n[![GitHub top language](https://img.shields.io/github/languages/top/ko1nksm/getoptions.svg)](https://github.com/ko1nksm/getoptions/search?l=Shell)\n[![License](https://img.shields.io/github/license/ko1nksm/getoptions.svg)](https://github.com/ko1nksm/getoptions/blob/master/LICENSE)\u003cbr\u003e\n![Linux](https://img.shields.io/badge/Linux-ecd53f?style=flat)\n![macOS](https://img.shields.io/badge/macOS-ecd53f?style=flat)\n![BSD](https://img.shields.io/badge/BSD-ecd53f?style=flat)\n![Solaris](https://img.shields.io/badge/Solaris-ecd53f?style=flat)\n![AIX](https://img.shields.io/badge/AIX-ecd53f?style=flat)\n![BusyBox](https://img.shields.io/badge/BusyBox-ecd53f?style=flat)\n![Windows](https://img.shields.io/badge/Windows-ecd53f?style=flat)\n![sh](https://img.shields.io/badge/sh-cec7d1.svg?style=flat)\n![bash](https://img.shields.io/badge/bash-cec7d1.svg?style=flat)\n![dash](https://img.shields.io/badge/dash-cec7d1.svg?style=flat)\n![ksh](https://img.shields.io/badge/ksh-cec7d1.svg?style=flat)\n![mksh](https://img.shields.io/badge/mksh-cec7d1.svg?style=flat)\n![yash](https://img.shields.io/badge/yash-cec7d1.svg?style=flat)\n![zsh](https://img.shields.io/badge/zsh-cec7d1.svg?style=flat)\n\nAn elegant option parser for shell scripts (full support for all POSIX shells)\n\n**getoptions** is a new option parser and generator written in POSIX-compliant shell script and released in august 2020.\nIt is for those who want to support the POSIX / GNU style option syntax in your shell scripts.\nMost easy, simple, fast, small, extensible and portable. No more any loops and templates needed!\n\n## TL; DR \u003c!-- omit in toc --\u003e\n\n```sh\n#!/bin/sh\n\nVERSION=\"0.1\"\n\nparser_definition() {\n  setup   REST help:usage -- \"Usage: example.sh [options]... [arguments]...\" ''\n  msg -- 'Options:'\n  flag    FLAG    -f --flag                 -- \"takes no arguments\"\n  param   PARAM   -p --param                -- \"takes one argument\"\n  option  OPTION  -o --option on:\"default\"  -- \"takes one optional argument\"\n  disp    :usage     --help\n  disp    VERSION    --version\n}\n\neval \"$(getoptions parser_definition) exit 1\"\n\necho \"FLAG: $FLAG, PARAM: $PARAM, OPTION: $OPTION\"\nprintf '%s\\n' \"$@\" # rest arguments\n```\n\nIt generates a simple [option parser code](#how-to-see-the-option-parser-code) internally and parses the following arguments.\n\n```console\n$ example.sh -f --flag -p value --param value -o --option -ovalue --option=value 1 2 3\nFLAG: 1, PARAM: value, OPTION: value\n1\n2\n3\n```\n\nAutomatic help generation is also provided.\n\n```console\n$ example.sh --help\n\nUsage: example.sh [options]... [arguments]...\n\nOptions:\n  -f, --flag                  takes no arguments\n  -p, --param PARAM           takes one argument\n  -o, --option[=OPTION]       takes one optional argument\n      --help\n      --version\n```\n\n## Table of Contents \u003c!-- omit in toc --\u003e\n\n- [Features](#features)\n- [`getopt` vs `getopts` vs `getoptions`](#getopt-vs-getopts-vs-getoptions)\n- [Requirements](#requirements)\n- [Installation](#installation)\n  - [Homebrew / Linuxbrew](#homebrew--linuxbrew)\n- [Usage](#usage)\n  - [Use as a command](#use-as-a-command)\n  - [Use as a library](#use-as-a-library)\n  - [Use as a generator](#use-as-a-generator)\n  - [Embedding into a file](#embedding-into-a-file)\n- [Benchmarks](#benchmarks)\n- [How to see the option parser code](#how-to-see-the-option-parser-code)\n  - [Arguments containing spaces and quotes](#arguments-containing-spaces-and-quotes)\n  - [Why reuse `OPTARG` and `OPTIND` for different purposes?](#why-reuse-optarg-and-optind-for-different-purposes)\n  - [About workarounds](#about-workarounds)\n- [References](#references)\n  - [Global functions](#global-functions)\n  - [Helper functions](#helper-functions)\n- [Examples](#examples)\n  - [Basic](#basic)\n  - [Advanced](#advanced)\n    - [Custom error handler](#custom-error-handler)\n    - [Custom helper functions](#custom-helper-functions)\n  - [Subcommand](#subcommand)\n  - [Prehook](#prehook)\n  - [Extension](#extension)\n  - [Practical example](#practical-example)\n- [NOTE: 2.x breaking changes](#note-2x-breaking-changes)\n- [NOTE: 3.x breaking changes](#note-3x-breaking-changes)\n- [For developers](#for-developers)\n  - [How to test getoptions](#how-to-test-getoptions)\n- [Changelog](#changelog)\n- [License](#license)\n\n## Features\n\n- **Full support for all POSIX shells**, no limitations, no bashisms\n- High portability, supports all platforms (Linux, macOS, Windows, etc) where works POSIX shells\n- Neither `getopt` nor `getopts` is used, and implemented with shell scripts only\n- Provides DSL-like shell script way to define parsers for flexibility and extensibility\n- No need for code generation from embedded special comments\n- Can be used as an **option parser generator** to run without `getoptions`\n- Support for POSIX [[1]][POSIX] and GNU [[2]][GNU1] [[3]][GNU2] compliant option syntax\n- Support for **long options**\n- Support for **subcommands**\n- Support for **abbreviation option**\n- Support for **automatic help generation**\n- Support for options to call action function\n- Support for validation and custom error handler\n- Works fast with small overhead and small file size (5KB - 8KB) library\n- No global variables are used (except the special variables `OPTARG` and `OPTIND`)\n- Only a minimum of one (and a maximum of three) global functions are defined as a library\n- No worry about license, it's public domain (Creative Commons Zero v1.0 Universal)\n\n[POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html\n[GNU1]: https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html\n[GNU2]: https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html\n\n## `getopt` vs `getopts` vs `getoptions`\n\n|                                 | getopt           | getopts               | getoptions            |\n| ------------------------------- | ---------------- | --------------------- | --------------------- |\n| Implementation                  | external command | shell builtin command | shell script          |\n| Portability                     | No               | Yes                   | Yes                   |\n| Short option beginning with `-` | ✔️                | ✔️                     | ✔️                     |\n| Short option beginning with `+` | ❌                | ⚠ zsh, ksh, mksh only | ✔️                     |\n| Combining short options         | ✔️                | ✔️                     | ✔️                     |\n| Long option beginning with `--` | ⚠ GNU only       | ❌                     | ✔️                     |\n| Long option beginning with `-`  | ⚠ GNU only       | ❌                     | ✔️ limited             |\n| Abbreviating long options       | ⚠ GNU only       | ❌                     | ✔️                     |\n| Optional argument               | ⚠ GNU only       | ❌                     | ✔️                     |\n| Option after arguments          | ⚠ GNU only       | ❌                     | ✔️                     |\n| Stop option parsing with `--`   | ✔️                | ✔️                     | ✔️                     |\n| Scanning modes                  | ⚠ GNU only       | ❌                     | ✔️ `+` and enhancement |\n| Subcommand                      | ❌                | ❌                     | ✔️                     |\n| Validation by pattern matching  | ❌                | ❌                     | ✔️                     |\n| Custom validation               | ❌                | ❌                     | ✔️                     |\n| Custom error handler            | ❌                | ✔️                     | ✔️ more flexible       |\n| Automatic help generation       | ❌                | ❌                     | ✔️                     |\n\n## Requirements\n\n**Almost no requirements.**\n\n- Any POSIX shells\n  - `dash` 0.5.4+, `bash` 2.03+, `ksh` 88+, `mksh` R28+, `zsh` 3.1.9+, `yash` 2.29+, busybox `ash` 1.1.3+, etc\n- Only `cat` is used for help display, but it can be removed\n\n## Installation\n\n**Download prebuild shell scripts** from [releases](https://github.com/ko1nksm/getoptions/releases).\n\n- getoptions: Option parser\n- gengetoptions: Option parser generator\n\n```sh\nwget https://github.com/ko1nksm/getoptions/releases/latest/download/getoptions -O $HOME/bin/getoptions\nchmod +x $HOME/bin/getoptions\n\n# optional\nwget https://github.com/ko1nksm/getoptions/releases/latest/download/gengetoptions -O $HOME/bin/gengetoptions\nchmod +x $HOME/bin/gengetoptions\n```\n\nOr build and install it yourself.\n\n```sh\ngit clone https://github.com/ko1nksm/getoptions.git\ncd getoptions\nmake\nmake install PREFIX=$HOME\n```\n\n### Homebrew\n\n```sh\nbrew tap ko1nksm/getoptions\nbrew install getoptions\n```\n\n## Usage\n\nSupport three ways of use. It is better to use it as a command at first,\nand then use it as a library or generator as needed.\n\n|      | command | library | generator |\n| ---- | ------- | ------- | --------- |\n| easy | ★★★     | ★★☆     | ★☆☆       |\n| fast | ★☆☆     | ★★☆     | ★★★       |\n\n### Use as a command\n\nUse the `getoptions` command that you installed on your system.\nThis assumes that you have the `getoptions` command installed,\nbut it is the easiest to use and is suitable for personal scripts.\n\nThe execution speed is slightly slower than using it as a library. (Approx. 15ms overhead)\n\n```sh\nparser_definition() {\n  setup REST help:usage -- \"Usage: example.sh [options]... [arguments]...\"\n  ...\n}\n\neval \"$(getoptions parser_definition parse) exit 1\"\nparse \"$@\"\neval \"set -- $REST\"\n```\n\nThe mysterious `exit 1` above is code for exiting when the `getoptions`\ncommand is not found. The last character output by `getoptions` is `#`.\n\nIf you omit the option parser name or use `-`, it will define the default option\nparser and parse arguments immediately.\n\n```sh\nparser_definition() {\n  setup REST help:usage -- \"Usage: example.sh [options]... [arguments]...\"\n  ...\n}\n\neval \"$(getoptions parser_definition) exit 1\"\n\n# The above means the same as the following code.\n# eval \"$(getoptions parser_definition getoptions_parse) exit 1\"\n# getoptions_parse \"$@\"\n# eval \"set -- $REST\"\n```\n\nHINT: Are you wondering why the external command can call a shell function?\n\nThe external command `getoptions` will output the shell function `getoptions`.\nThe external command `getoptions` will be hidden by the shell function `getoptions` that defined by `eval`,\nand the `getoptions` will be called again, so it can be call the shell function `parser_definition`.\n\nTry running the following command to see what is output.\n\n```console\n$ getoptions parser_definition parse\n```\n\n### Use as a library\n\nThe `getoptions` command is not recommended for use in distribution scripts\nbecause it is not always installed on the system. This problem can be solved by\nincluding getoptions as a shell script library in your shell scripts.\n\nTo use getoptions as a library, you need to generate a library using the `gengetoptions` command.\nYou can optionally adjust the indentation and other settings when generating the library.\n\n```console\n$ gengetoptions library \u003e getoptions.sh\n```\n\n```sh\n. ./getoptions.sh # Or include it here\n\nparser_definition() {\n  setup REST help:usage -- \"Usage: example.sh [options]... [arguments]...\"\n  ...\n}\n\neval \"$(getoptions parser_definition parse)\"\nparse \"$@\"\neval \"set -- $REST\"\n```\n\nNOTE for 1.x and 2.x users: The previous version guided you to use `lib/*.sh`.\nThis is still available, but it is recommended to use `gengetoptions library`.\n\n### Use as a generator\n\nIf you do not want to include getoptions in your shell scripts, you can pre-generate an option parser.\nIt also runs the fastest, so it suitable when you need a lot of options.\n\n```console\n$ gengetoptions parser -f examples/parser_definition.sh parser_definition parse prog \u003e parser.sh\n```\n\n```sh\n. ./parser.sh # Or include it here\n\nparse \"$@\"\neval \"set -- $REST\"\n```\n\n### Embedding into a file\n\nYou can use `gengetoptions embed` to embed the generated code in a file,\nwhich makes maintenance easier.\n\nIf you want to write the parser definition in the same file as\nthe shell script to execute, define it between `@getoptions` and `@end`.\nThe code contained here will be executed during code generation.\n\nThe generated code will be embedded between the `@gengetoptions` and `@end` directives.\nThe arguments of `@gengetoptions` are the same as the arguments of the `gengetoptions` command,\nwhich allows you to embed the library as well as the parser.\n\nExample\n\n**example.sh**\n\n```sh\n#!/bin/sh\n\nset -eu\n\n# @getoptions\nparser_definition() {\n  setup   REST help:usage -- \"Usage: example.sh [options]... [arguments]...\" ''\n  msg -- 'Options:'\n  flag    FLAG    -f --flag                 -- \"takes no arguments\"\n  param   PARAM   -p --param                -- \"takes one argument\"\n  option  OPTION  -o --option on:\"default\"  -- \"takes one optional argument\"\n  disp    :usage  -h --help\n  disp    VERSION    --version\n}\n# @end\n\n# @gengetoptions parser -i parser_definition parse\n#\n#     INSERTED HERE\n#\n# @end\n\nparse \"$@\"\neval \"set -- $REST\"\n\necho \"FLAG: $FLAG, PARAM: $PARAM, OPTION: $OPTION\"\nprintf '%s\\n' \"$@\" # rest arguments\n```\n\n```console\n$ gengetoptions embed --overwrite example.sh\n```\n\n## Benchmarks\n\nUbuntu (dash) Core i7 3.4 Ghz\n\n```ini\n[Use as command]\nBenchmark 1: sh ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):       4.9 ms ±   0.2 ms    [User: 4.8 ms, System: 0.6 ms]\n  Range (min … max):     4.5 ms …   5.8 ms    479 runs\n\n[Use as library]\nBenchmark 1: sh ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):       4.1 ms ±   0.2 ms    [User: 3.9 ms, System: 0.4 ms]\n  Range (min … max):     3.7 ms …   5.0 ms    661 runs\n\n[Use as generator]\nBenchmark 1: sh ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):     827.0 µs ±  77.0 µs    [User: 759.0 µs, System: 100.1 µs]\n  Range (min … max):   702.2 µs … 3044.5 µs    2293 runs\n```\n\nUbuntu (bash) Core i7 3.4 Ghz\n\n```ini\n[Use as command]\nBenchmark 1: bash ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):      18.9 ms ±   0.6 ms    [User: 17.9 ms, System: 1.5 ms]\n  Range (min … max):    17.7 ms …  22.0 ms    153 runs\n\n[Use as library]\nBenchmark 1: bash ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):      17.7 ms ±   0.6 ms    [User: 16.8 ms, System: 1.4 ms]\n  Range (min … max):    16.5 ms …  19.8 ms    160 runs\n\n[Use as generator]\nBenchmark 1: bash ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):       2.4 ms ±   0.2 ms    [User: 2.1 ms, System: 0.4 ms]\n  Range (min … max):     2.1 ms …   5.3 ms    882 runs\n```\n\nmacOS (bash), Core i5 2.4 GHz\n\n```ini\n[Use as command]\nBenchmark 1: sh ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):      68.5 ms ±   5.5 ms    [User: 55.2 ms, System: 12.3 ms]\n  Range (min … max):    63.8 ms …  87.8 ms    33 runs\n\n[Use as library]\nBenchmark 1: sh ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):      57.1 ms ±   3.6 ms    [User: 49.4 ms, System: 7.3 ms]\n  Range (min … max):    54.3 ms …  75.7 ms    47 runs\n\n[Use as generator]\nBenchmark 1: sh ./example.sh --flag1 --flag2 --flag3 --param1 param1 --param2 param2 --param3 param3 --option1=option1 --option2=option2 --option3=option3 a b c d e f g\n  Time (mean ± σ):       9.6 ms ±   2.3 ms    [User: 4.6 ms, System: 3.9 ms]\n  Range (min … max):     7.4 ms …  19.2 ms    125 runs\n```\n\n## How to see the option parser code\n\nIt is important to know what kind of code is being generated\nwhen the option parser is not working as expected.\n\nIf you want to see the option parser code, rewrite it as follows.\n\n```sh\n# eval \"$(getoptions parser_definition parse) exit 1\"\n\n# Preload the getoptions library\n# (can be omitted when using getoptions as a library)\neval \"$(getoptions -)\"\n\n# Output of the option parser\ngetoptions parser_definition parse\nexit\n```\n\nThe option parsing code generated by getoptions is very simple.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample option parser code\u003c/summary\u003e\n\n```sh\nFLAG=''\nPARAM=''\nOPTION=''\nREST=''\nparse() {\n  OPTIND=$(($#+1))\n  while OPTARG= \u0026\u0026 [ $# -gt 0 ]; do\n    case $1 in\n      --?*=*) OPTARG=$1; shift\n        eval 'set -- \"${OPTARG%%\\=*}\" \"${OPTARG#*\\=}\"' ${1+'\"$@\"'}\n        ;;\n      --no-*|--without-*) unset OPTARG ;;\n      -[po]?*) OPTARG=$1; shift\n        eval 'set -- \"${OPTARG%\"${OPTARG#??}\"}\" \"${OPTARG#??}\"' ${1+'\"$@\"'}\n        ;;\n      -[fh]?*) OPTARG=$1; shift\n        eval 'set -- \"${OPTARG%\"${OPTARG#??}\"}\" -\"${OPTARG#??}\"' ${1+'\"$@\"'}\n        OPTARG= ;;\n    esac\n    case $1 in\n      '-f'|'--flag')\n        [ \"${OPTARG:-}\" ] \u0026\u0026 OPTARG=${OPTARG#*\\=} \u0026\u0026 set \"noarg\" \"$1\" \u0026\u0026 break\n        eval '[ ${OPTARG+x} ] \u0026\u0026:' \u0026\u0026 OPTARG='1' || OPTARG=''\n        FLAG=\"$OPTARG\"\n        ;;\n      '-p'|'--param')\n        [ $# -le 1 ] \u0026\u0026 set \"required\" \"$1\" \u0026\u0026 break\n        OPTARG=$2\n        PARAM=\"$OPTARG\"\n        shift ;;\n      '-o'|'--option')\n        set -- \"$1\" \"$@\"\n        [ ${OPTARG+x} ] \u0026\u0026 {\n          case $1 in --no-*|--without-*) set \"noarg\" \"${1%%\\=*}\"; break; esac\n          [ \"${OPTARG:-}\" ] \u0026\u0026 { shift; OPTARG=$2; } || OPTARG='default'\n        } || OPTARG=''\n        OPTION=\"$OPTARG\"\n        shift ;;\n      '-h'|'--help')\n        usage\n        exit 0 ;;\n      '--version')\n        echo \"${VERSION}\"\n        exit 0 ;;\n      --)\n        shift\n        while [ $# -gt 0 ]; do\n          REST=\"${REST} \\\"\\${$(($OPTIND-$#))}\\\"\"\n          shift\n        done\n        break ;;\n      [-]?*) set \"unknown\" \"$1\"; break ;;\n      *)\n        REST=\"${REST} \\\"\\${$(($OPTIND-$#))}\\\"\"\n    esac\n    shift\n  done\n  [ $# -eq 0 ] \u0026\u0026 { OPTIND=1; unset OPTARG; return 0; }\n  case $1 in\n    unknown) set \"Unrecognized option: $2\" \"$@\" ;;\n    noarg) set \"Does not allow an argument: $2\" \"$@\" ;;\n    required) set \"Requires an argument: $2\" \"$@\" ;;\n    pattern:*) set \"Does not match the pattern (${1#*:}): $2\" \"$@\" ;;\n    notcmd) set \"Not a command: $2\" \"$@\" ;;\n    *) set \"Validation error ($1): $2\" \"$@\"\n  esac\n  echo \"$1\" \u003e\u00262\n  exit 1\n}\nusage() {\ncat\u003c\u003c'GETOPTIONSHERE'\nUsage: example.sh [options]... [arguments]...\n\nOptions:\n  -f, --flag                  takes no arguments\n  -p, --param PARAM           takes one argument\n  -o, --option[=OPTION]       takes one optional argument\n  -h, --help\n      --version\nGETOPTIONSHERE\n}\n# Do not execute\n```\n\n\u003c/details\u003e\n\n### Arguments containing spaces and quotes\n\nThe getoptions correctly handles arguments containing spaces and quotes\nwithout using arrays, which are not available in POSIX shells.\n\nThe magic is in the `REST` variable in the following code.\n\n```sh\n$ examples.sh --flag 1 --param value 2 -- 3\n\n# examples.sh\n...\neval \"$(getoptions parser_definition parse \"$0\") exit 1\"\nparse \"$@\"\neval \"set -- $REST\"\n\necho \"$REST\" # =\u003e \"${2}\" \"${5}\" \"${7}\"\necho \"$@\" # =\u003e 1 2 3\n...\n```\n\n### Why reuse `OPTARG` and `OPTIND` for different purposes?\n\nThis is to avoid using valuable global variables. The POSIX shell does not have local variables.\nInstead of using long variable names to avoid conflicts, we reuse `OPTARG` and `OPTIND`.\nThis code has been tested to work without any problem with all POSIX shells (e.g. ksh88, bash 2.03).\n\nIf you use `getoptions` instead of `getopts` for option parsing, `OPTARG` and `OPTIND` are not needed.\nIn addition, you can also use `getopts`, since `OPTARG` and `OPTIND` will be correctly reset after use.\n\nIf you still don't like it, you can use the `--optarg` and `--optind` options of `gengetoptions` to change the variable name.\nIn addition, since the license of `getoptions` is CC0, you can modify it to use it as you like.\n\n### About workarounds\n\nThe option parser code contains workarounds for some shell bugs.\nIf you want to know what that code means, please refer to [Workarounds.md](docs/Workarounds.md).\n\n## References\n\nFor more information, see [References](docs/References.md).\n\n### Global functions\n\nWhen the `getoptions` is used as an external command, three global functions,\n`getoptions`, `getoptions_help`, and `getoptions_abbr`, are defined in your shell script.\n\nIf you are using it as a library, only `getoptions` is required.\nThe other functions are needed when the corresponding features are used.\n\n### Helper functions\n\nHelper functions are  (`setup`, `flag`, `param`, etc) used to define option parsers,\nand are defined only within the global functions described above.\n\n## Examples\n\n### Basic\n\n[basic.sh](examples/basic.sh)\n\nThis is an example of basic usage. It should be enough for your personal script.\n\n### Advanced\n\n[advanced.sh](examples/advanced.sh)\n\nShell scripts distributed as utilities may require advanced features and validation.\n\n#### Custom error handler\n\nBy defining the custom error handler, you can change the standard error messages,\nrespond to additional error messages, and change the exit status.\n\n#### Custom helper functions\n\nBy defining your own helper functions, you can easily define advanced options.\nFor example, getoptions does not have a helper function to assign to the array,\nbut it can be easily implemented by a custom helper function.\n\n### Subcommand\n\n[subcmd.sh](examples/subcmd.sh)\n\nComplex programs are often implemented using subcommands.\nWhen using subcommands in getoptions, parse the arguments multiple times.\n(For example, parse up to the subcommand, and then parse after it.\nThis design is useful for splitting shell scripts by each subcommand.\n\n### Prehook\n\n[prehook.sh](examples/prehook.sh)\n\nIf you define a `prehook` function in the parser definition,\nit will be calledbefore helper functions is called.\nThis allows you to process the arguments before calling the helper function.\n\nThis feature was originally designed to handle variable names with prefixes\nwithout complicating getoptions. Therefore, it may not be very flexible.\n\nNOTE: The `prehook` function is not called in the help.\n\n### Extension\n\nTODO: ~~[extension.sh](examples/extension.sh)~~\n\nRecall that the parser definition function is just a shell script.\nYou can extend the functionality by calling it from your function.\nFor example, you could add a `required` attribute that means nonsense required options.\n\n### Practical example\n\ngetoptions was originally developed to improve the maintainability and testability for [ShellSpec][shellspec]\nwhich has number of options. [ShellSpec optparser][optparser] is another good example of how to use getoptions.\n\n[shellspec]: https://shellspec.info/\n[optparser]: https://github.com/shellspec/shellspec/tree/master/lib/libexec/optparser\n\n## NOTE: 2.x breaking changes\n\n- Calling `getoptions_help` is no longer needed (see `help` attribute)\n- Changed the `default` attribute of the `option` helper function to the `on` attribute\n- Improved the custom error handler and changed the arguments\n- Disable expansion variables in the help display\n\n## NOTE: 3.x breaking changes\n\n- Renamed `lib/getoptions.sh` to `lib/getoptions_base.sh`\n- Renamed `getoptions-cli` to `gengetoptions`\n- Moved library generation feature of `getoptions` to `gengetoptions`\n- Removed scanning mode `=` and `#`\n- Changed attribute `off` to `no`\n- Changed initial value `@off` to `@no`\n\n## For developers\n\n### How to test getoptions\n\nTests are executed using [shellspec](https://github.com/shellspec/shellspec).\n\n```sh\n# Install shellspec (if not installed)\ncurl -fsSL https://git.io/shellspec | sh\n\n# Run tests\nshellspec\n\n# Run tests with other shell\nshellspec --shell bash\n```\n\nNOTE: Currently, only the option parser is being tested,\nand the CLI utilities is not being tested.\n\n## Changelog\n\n[CHANGELOG.md](CHANGELOG.md)\n\n## License\n\n[Creative Commons Zero v1.0 Universal](https://github.com/ko1nksm/getoptions/blob/master/LICENSE)\n\nAll rights are relinquished and you can used as is or modified in your project.\nNo credit is also required, but I would appreciate it if you could credit me as the original author.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fko1nksm%2Fgetoptions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fko1nksm%2Fgetoptions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fko1nksm%2Fgetoptions/lists"}