You've already forked sh-args-parser
mirror of
https://github.com/nikolaypronchev/sh-args-parser.git
synced 2026-04-24 00:46:32 +03:00
Compare commits
9 Commits
c55c4383d2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
dad2d2a862
|
|||
|
1cfda0033c
|
|||
| 70e03cf213 | |||
| eb4927a3ee | |||
| 45138ce80c | |||
| 4e979574d8 | |||
| 5f3b3c693f | |||
| 6887a39f03 | |||
| 67e6bf8567 |
121
README.md
121
README.md
@@ -1,6 +1,6 @@
|
||||
# Sh args parser
|
||||
|
||||
This is POSIX-compliant code for parsing shell script arguments. It helps you focus on writing the script logic by separating argument parsing and basic validation.
|
||||
This is POSIX-compliant parser for script arguments. It helps you focus on writing the script logic by separating argument parsing and basic validation.
|
||||
|
||||
## Contents
|
||||
|
||||
@@ -14,14 +14,36 @@ This is POSIX-compliant code for parsing shell script arguments. It helps you fo
|
||||
|
||||
## Installation
|
||||
|
||||
Include the `parser.sh` file in your script using [`dot`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#dot) or [`source`](https://www.gnu.org/software/bash/manual/bash.html#index-source).
|
||||
|
||||
Include `parser.sh` content before usage. The most convenient way is to include the `parser.sh` file in your script using [`dot`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#dot) or [`source`](https://www.gnu.org/software/bash/manual/bash.html#index-source) shell built-ins.
|
||||
It is important to note that external files are included relative to the terminal's current directory, not the script's directory. If you decide to include files using a path relative to the script, use the following approach:
|
||||
```bash
|
||||
#!/usr/bin/env sh
|
||||
. parser.sh
|
||||
script_dir="$(dirname "$(readlink -f "$0")")"
|
||||
. "$script_dir/parser.sh"
|
||||
```
|
||||
This will allow you to include the `parser.sh` from the script's directory, regardless of where you run the script from.
|
||||
### Git submodule
|
||||
|
||||
It is convenient to include parser in your repository as a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules):
|
||||
```bash
|
||||
git submodule add https://github.com/nikolaypronchev/sh-args-parser.git
|
||||
```
|
||||
The repository `nikolaypronchev/sh-args-parser` will be copied into your repository in the `sh-args-parser` directory:
|
||||
```
|
||||
your-repo/
|
||||
├ sh-args-parser/
|
||||
| ├ parser.sh
|
||||
| └ ...
|
||||
├ your-script.sh
|
||||
└ ...
|
||||
```
|
||||
Next, include `parser.sh` in your script using the approach from the previous section:
|
||||
```bash
|
||||
# your-script.sh
|
||||
script_dir="$(dirname "$(readlink -f "$0")")"
|
||||
. "$script_dir/sh-args-parser/parser.sh"
|
||||
```
|
||||
|
||||
Or copy the contents of the `parser.sh` file into your script.
|
||||
It’s important to remember that submodules are not fetched by Git by default when running `git clone`. To clone your repository including submodules, use the command `git clone --recurse-submodules`.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -71,7 +93,7 @@ A command typically represents the core action performed by the script: `run`, `
|
||||
|
||||
- Positional arguments are placed after the command, if present.
|
||||
- The presence and number of positional arguments are determined by the script's logic.
|
||||
- After the special argument --, all arguments are considered positional. This allows passing arguments that start with a dash and might be confused with options.
|
||||
- After the special argument `--`, all arguments are considered positional. This allows passing arguments that start with a dash and might be confused with options.
|
||||
|
||||
### Options
|
||||
Options are script parameters. Each option has at least one alias by which it can be specified in the command line. Options often have both short and long aliases, such as `-h` and `--help`.
|
||||
@@ -83,30 +105,48 @@ Options are script parameters. Each option has at least one alias by which it ca
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is defined by assigning values to variables before using the parser. For example:
|
||||
|
||||
```bash
|
||||
_accept_command=true
|
||||
```
|
||||
Configuration variables must be assigned before calling `_parse`.
|
||||
Configuration is done by assigning values to special keys via [`_set_config`](#_set_config) before using [`_parse`](#_parse).
|
||||
|
||||
| Name | Default Value | Description |
|
||||
| --- | --- | --- |
|
||||
| _accept_command | `auto` | `any` — The script accepts a command.<br>`none` — The script does not accept a command.<br>`mapped_only` — The script accepts only a mapped command.<br>`auto` — The script accepts a command if at least one has been mapped. |
|
||||
| _accept_options | `auto` | `any` — The script accepts any options.<br>`none` — The script does not accept any options.<br>`mapped_only` — The script accepts only mapped options.<br>`auto` — The script accepts only mapped options if at least one has been mapped. Otherwise, it accepts any options. |
|
||||
| _default_max_positional_args | | Maximum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
|
||||
| _default_min_positional_args | `0` | Minimum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
|
||||
| _mapping_key_value_delimiter | `=` | Key-value delimiter for options mapping (see [_map_option](#_map_option)). |
|
||||
| _mapping_values_delimiter | `,` | Values delimiter for options mapping (see [_map_option](#_map_option)). |
|
||||
| _option_duplicates_allowed | `false` | `true` — Multiple uses of options are allowed.<br>`false` — Multiple uses of options are not allowed.|
|
||||
| _option_key_value_delimiter | `' '` | Option alias-args delimiter. |
|
||||
| _option_values_delimiter | `' '` | Option values delimiter. |
|
||||
| _options_combination_allowed | `true` | `true` — Combining short option aliases into combinations is allowed.<br>`false` — Combining short option aliases is not allowed. |
|
||||
| _options_combination_args_allowed | `true` | `true` — Passing arguments to the last option in a combination is allowed.<br>`false` — Passing arguments to the last option in a combination is not allowed. |
|
||||
| _positional_args_placement | `any` | `any` — Positional arguments can be placed anywhere, including mixed with options.<br>`before_options` — Positional arguments are placed before options.<br>`after_options` — Positional arguments are placed after options. |
|
||||
| accept_command | `auto` | `any` — The script accepts a command.<br>`none` — The script does not accept a command.<br>`mapped_only` — The script accepts only a mapped command.<br>`auto` — The script accepts a command if at least one has been mapped. |
|
||||
| accept_options | `auto` | `any` — The script accepts any options.<br>`none` — The script does not accept any options.<br>`mapped_only` — The script accepts only mapped options.<br>`auto` — The script accepts only mapped options if at least one has been mapped. Otherwise, it accepts any options. |
|
||||
| default_max_positional_args | | Maximum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
|
||||
| default_min_positional_args | `0` | Minimum number of positional arguments. A different value can be set for each command (see [_map_command](#_map_command)). |
|
||||
| default_positional_arg_variable || Name of the variable that will store the single positional argument. Implicitly sets `_default_max_positional_args` and `_default_min_positional_args` to 1. Command-specific values for `max_args` and `arg_variable` disables this behavior. |
|
||||
| mapping_key_value_delimiter | `=` | Key-value delimiter for options mapping (see [_map_option](#_map_option)). Allowed values: `=` `:`.|
|
||||
| mapping_values_delimiter | `,` | Values delimiter for options mapping (see [_map_option](#_map_option)). Allowed values: `,` `;` `\|` `/`.|
|
||||
| option_duplicates_allowed | `false` | `true` — Multiple uses of options are allowed.<br>`false` — Multiple uses of options are not allowed.|
|
||||
| option_key_value_delimiter | `' '` | Option alias-args delimiter. Allowed values: `' '` `=` `:`.|
|
||||
| option_values_delimiter | `' '` | Option values delimiter. Allowed values: `' '` `,` `;` `\|` `/`.|
|
||||
| options_combination_allowed | `true` | `true` — Combining short option aliases into combinations is allowed.<br>`false` — Combining short option aliases is not allowed. |
|
||||
| options_combination_args_allowed | `true` | `true` — Passing arguments to the last option in a combination is allowed.<br>`false` — Passing arguments to the last option in a combination is not allowed. |
|
||||
| positional_args_placement | `any` | `any` — Positional arguments can be placed anywhere, including mixed with options.<br>`before_options` — Positional arguments are placed before options.<br>`after_options` — Positional arguments are placed after options. |
|
||||
|
||||
## Functions
|
||||
|
||||
- [_set_config](#_set_config)
|
||||
- [_parse](#_parse)
|
||||
- [Functions for command and option mapping](#functions-for-command-and-option-mapping):
|
||||
- [_map_command](#_map_command)
|
||||
- [_map_option](#_map_option)
|
||||
- [Functions for working with parsing results](#functions-for-working-with-parsing-results):
|
||||
- [_get_command](#_get_command)
|
||||
- [_is_used_command](#_is_used_command)
|
||||
- [_get_positional_args](#_get_positional_args)
|
||||
- [_get_positional_args_count](#_get_positional_args_count)
|
||||
- [_get_positional_arg](#_get_positional_arg)
|
||||
- [_is_used_option](#_is_used_option)
|
||||
- [_get_option_args](#_get_option_args)
|
||||
- [_get_option_args_count](#_get_option_args_count)
|
||||
- [_get_option_arg](#_get_option_arg)
|
||||
|
||||
#### _set_config
|
||||
Sets the configuration variables. Full list of configuration variables and expected values can be found in the [Configuration](#configuration) section.
|
||||
```bash
|
||||
_set_config '_accept_command' 'any'
|
||||
```
|
||||
|
||||
#### _parse
|
||||
Parses the provided arguments. Typically, takes all command-line arguments `$@` as input.
|
||||
```bash
|
||||
@@ -131,6 +171,7 @@ Maps a command. Takes key-value pairs as arguments. Key and values list are sepa
|
||||
| description | Command description. Currently not used. |
|
||||
| min_args | Minimum number of positional arguments when using the command. |
|
||||
| max_args | Maximum number of positional arguments when using the command. |
|
||||
| arg_variable | Name of the variable that will store the command's positional argument. Implicitly sets `min_args` and `max_args` to 1. |
|
||||
|
||||
```bash
|
||||
_map_command \
|
||||
@@ -194,6 +235,20 @@ _is_used_command bar && echo 'Command "bar" was used'
|
||||
Command "foo" was used
|
||||
```
|
||||
|
||||
#### _get_positional_args
|
||||
|
||||
Outputs the positional arguments separated by space. Delimiter can be changed by passing it's value as the first argument.
|
||||
|
||||
```bash
|
||||
_parse foo bar baz
|
||||
_get_positional_args
|
||||
_get_positional_args "|"
|
||||
```
|
||||
```
|
||||
foo bar baz
|
||||
foo|bar|baz
|
||||
```
|
||||
|
||||
#### _get_positional_args_count
|
||||
|
||||
Outputs the number of positional arguments.
|
||||
@@ -236,6 +291,20 @@ Option "--bar" was used
|
||||
Option "-c" was used
|
||||
```
|
||||
|
||||
#### _get_option_args
|
||||
|
||||
Outputs the arguments of the option separated by space. Mandatory option alias is expected as the first argument. Delimiter can be changed by passing it's value as the second argument.
|
||||
|
||||
```bash
|
||||
_parse -v foo bar baz
|
||||
_get_option_args -v
|
||||
_get_option_args -v "|"
|
||||
```
|
||||
```
|
||||
foo bar baz
|
||||
foo|bar|baz
|
||||
```
|
||||
|
||||
#### _get_option_args_count
|
||||
|
||||
Outputs the number of arguments for the option with the alias passed as the first argument.
|
||||
@@ -263,8 +332,6 @@ baz
|
||||
```
|
||||
|
||||
## TODO
|
||||
- Add "Debug" mode with verbose output;
|
||||
- Bug: required + variable/variable_value makes no sense as it makes option variable constant;
|
||||
- Add examples;
|
||||
- Implement "Help" generation;
|
||||
- Add tests.
|
||||
|
||||
314
parser.sh
314
parser.sh
@@ -4,6 +4,7 @@ _accept_command=auto # auto, none, any, mapped_only
|
||||
_accept_options=auto # auto, none, any, mapped_only
|
||||
_default_max_positional_args=""
|
||||
_default_min_positional_args=0
|
||||
_default_positional_arg_variable=""
|
||||
_mapping_key_value_delimiter="="
|
||||
_mapping_values_delimiter=","
|
||||
_option_duplicates_allowed=true
|
||||
@@ -51,6 +52,10 @@ _is_int() {
|
||||
esac
|
||||
}
|
||||
|
||||
_is_flag() {
|
||||
[ "$1" = "true" ] || [ "$1" = "false" ]
|
||||
}
|
||||
|
||||
_assign() {
|
||||
if ! _is_valid_var_name "$1"; then
|
||||
_err "Invalid variable name: $1."
|
||||
@@ -151,6 +156,72 @@ _mapped_options_only() {
|
||||
[ "$_mapped_options_count" -gt 0 ]
|
||||
}
|
||||
|
||||
_is_free_var_name() {
|
||||
if [ -n "$_default_positional_arg_variable" ] && [ "$_default_positional_arg_variable" = "$1" ]; then
|
||||
echo "Variable is already used as default positional arg variable: $1."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_i=1
|
||||
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
|
||||
echo "Variable is already mapped for option #${_i}: $1."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_i=$(_math "$_i + 1")
|
||||
done
|
||||
|
||||
_i=1
|
||||
while [ "$_i" -le "$_mapped_commands_count" ]; do
|
||||
if [ "$1" = "$(_var_value "_commands_${_i}_arg_variable")" ]; then
|
||||
echo "Arg variable is already mapped for command #${_i}: $1."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_i=$(_math "$_i + 1")
|
||||
done
|
||||
}
|
||||
|
||||
_set_config() {
|
||||
_config_key="$1"
|
||||
_config_value="$2"
|
||||
|
||||
if [ "$_config_key" = "accept_command" ]; then
|
||||
_validate_config_accept_command "$_config_value"
|
||||
elif [ "$_config_key" = "accept_options" ]; then
|
||||
_validate_config_accept_options "$_config_value"
|
||||
elif [ "$_config_key" = "default_max_positional_args" ]; then
|
||||
_validate_config_default_max_positional_args "$_config_value"
|
||||
elif [ "$_config_key" = "default_min_positional_args" ]; then
|
||||
_validate_config_default_min_positional_args "$_config_value"
|
||||
elif [ "$_config_key" = "default_positional_arg_variable" ]; then
|
||||
_validate_config_default_positional_arg_variable "$_config_value"
|
||||
_default_max_positional_args="1"
|
||||
_default_min_positional_args="1"
|
||||
elif [ "$_config_key" = "mapping_key_value_delimiter" ]; then
|
||||
_validate_config_mapping_key_value_delimiter "$_config_value"
|
||||
elif [ "$_config_key" = "mapping_values_delimiter" ]; then
|
||||
_validate_config_mapping_values_delimiter "$_config_value"
|
||||
elif [ "$_config_key" = "option_duplicates_allowed" ]; then
|
||||
_validate_config_option_duplicates_allowed "$_config_value"
|
||||
elif [ "$_config_key" = "option_key_value_delimiter" ]; then
|
||||
_validate_config_option_key_value_delimiter "$_config_value"
|
||||
elif [ "$_config_key" = "option_values_delimiter" ]; then
|
||||
_validate_config_option_values_delimiter "$_config_value"
|
||||
elif [ "$_config_key" = "options_combination_allowed" ]; then
|
||||
_validate_config_options_combination_allowed "$_config_value"
|
||||
elif [ "$_config_key" = "options_combination_args_allowed" ]; then
|
||||
_validate_config_options_combination_args_allowed "$_config_value"
|
||||
elif [ "$_config_key" = "positional_args_placement" ]; then
|
||||
_validate_config_positional_args_placement "$_config_value" # TODO
|
||||
else
|
||||
_err "Unknown config key: $_config_key."
|
||||
fi
|
||||
|
||||
_assign "_$_config_key" "$_config_value"
|
||||
}
|
||||
|
||||
_map_command() {
|
||||
_command_index=$(_math "$_mapped_commands_count + 1")
|
||||
_mapping_command_prefix="_commands_${_command_index}"
|
||||
@@ -179,6 +250,10 @@ _map_command() {
|
||||
_validate_command_min_args "$_map_value"
|
||||
elif [ "$_map_key" = "name" ]; then
|
||||
_validate_command_name "$_map_value"
|
||||
elif [ "$_map_key" = "arg_variable" ]; then
|
||||
_validate_command_arg_variable "$_map_value"
|
||||
_assign "${_mapping_command_prefix}_min_args" 1
|
||||
_assign "${_mapping_command_prefix}_max_args" 1
|
||||
else
|
||||
_err "Invalid command #${_command_index} mapping key: $_map_key."
|
||||
fi
|
||||
@@ -233,6 +308,8 @@ _map_option() {
|
||||
_validate_option_aliases "$_map_value"
|
||||
elif [ "$_map_key" = "variable" ]; then
|
||||
_validate_option_variable "$_map_value"
|
||||
_assign "${_mapping_option_prefix}_min_args" 1
|
||||
_assign "${_mapping_option_prefix}_max_args" 1
|
||||
elif [ "$_map_key" = "description" ]; then
|
||||
_validate_option_description "$_map_value"
|
||||
elif [ "$_map_key" = "max_args" ]; then
|
||||
@@ -272,6 +349,131 @@ _map_option_auto() {
|
||||
_mapped_options_count=$_option_index
|
||||
}
|
||||
|
||||
_validate_config_accept_command() {
|
||||
case "$1" in
|
||||
any | none | mapped_only | auto)
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_accept_command\" value: $1. Expected: any, none, mapped_only, auto."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_validate_config_accept_options() {
|
||||
case "$1" in
|
||||
any | none | mapped_only | auto)
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_accept_options\" value: $1. Expected: any, none, mapped_only, auto."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_validate_config_default_max_positional_args() {
|
||||
if ! _is_int "$1"; then
|
||||
_err "Invalid config \"_default_max_positional_args\" value: $1. Expected: a non-negative integer."
|
||||
fi
|
||||
|
||||
if [ -n "$_default_positional_arg_variable" ] && [ "$1" -ne 1 ]; then
|
||||
_err "Config \"_default_max_positional_args\" cannot differ from 1 if \"_default_positional_arg_variable\" is set."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_default_min_positional_args() {
|
||||
if ! _is_int "$1"; then
|
||||
_err "Invalid config \"_default_min_positional_args\" value: $1. Expected: a non-negative integer."
|
||||
fi
|
||||
|
||||
if [ -n "$_default_positional_arg_variable" ] && [ "$1" -ne 1 ]; then
|
||||
_err "Config \"_default_min_positional_args\" cannot differ from 1 if \"_default_positional_arg_variable\" is set."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_default_positional_arg_variable() {
|
||||
if ! _is_valid_var_name "$1"; then
|
||||
_err "Default positional arg variable is invalid: $1. Must be a valid variable name."
|
||||
fi
|
||||
|
||||
if ! _description=$(_is_free_var_name "$1"); then
|
||||
_err "Default positional arg is already used. ${_description}"
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_mapping_key_value_delimiter() {
|
||||
case "$1" in
|
||||
"=" | ":")
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_mapping_key_value_delimiter\" value: $1. Expected: \"=\", \":\"."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_validate_config_mapping_values_delimiter() {
|
||||
case "$1" in
|
||||
"," | "|" | ";" | "/")
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_mapping_values_delimiter\" value: $1. Expected: \",\", \"|\", \";\", \"/\"."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_validate_config_option_duplicates_allowed() {
|
||||
if ! _is_flag "$1"; then
|
||||
_err "Invalid config \"_option_duplicates_allowed\" value: $1. Expected \"true\" or \"false\"."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_option_key_value_delimiter() {
|
||||
case "$1" in
|
||||
" " | "=" | ":")
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_option_key_value_delimiter\" value: $1. Expected: \" \", \"=\", \":\"."
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$1" != " " ] && [ "$_option_key_value_delimiter" = " " ]; then
|
||||
_err "Non-space value of config \"_option_key_value_delimiter\" is incompatible with space valueof config \"_option_values_delimiter\" due to parsing ambiguity."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_option_values_delimiter() {
|
||||
case "$1" in
|
||||
" " |"," | "|" | ";" | "/")
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_mapping_values_delimiter\" value: $1. Expected: \" \", \",\", \"|\", \";\", \"/\"."
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$1" = " " ] && [ "$_option_key_value_delimiter" != " " ]; then
|
||||
_err "Non-space value of config \"_option_key_value_delimiter\" is incompatible with space valueof config \"_option_values_delimiter\" due to parsing ambiguity."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_options_combination_allowed() {
|
||||
if ! _is_flag "$1"; then
|
||||
_err "Invalid config \"_options_combination_allowed\" value: $1. Expected \"true\" or \"false\"."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_options_combination_args_allowed() {
|
||||
if ! _is_flag "$1"; then
|
||||
_err "Invalid config \"_options_combination_args_allowed\" value: $1. Expected \"true\" or \"false\"."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_config_positional_args_placement() {
|
||||
case "$1" in
|
||||
any | before_options | after_options)
|
||||
;;
|
||||
*)
|
||||
_err "Invalid config \"_positional_args_placement\" value: $1. Expected: any, before_options, after_options."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_validate_command_description() {
|
||||
if [ -n "$(_var_value "${_mapping_command_prefix}_description")" ]; then
|
||||
@@ -345,6 +547,31 @@ _validate_command_name() {
|
||||
done
|
||||
}
|
||||
|
||||
_validate_command_arg_variable() {
|
||||
if [ -n "$(_var_value "${_mapping_command_prefix}_arg_variable")" ]; then
|
||||
_err "Command #${_command_index} arg variable is already mapped."
|
||||
fi
|
||||
|
||||
_min_args=$(_var_value "${_mapping_command_prefix}_min_args")
|
||||
_max_args=$(_var_value "${_mapping_command_prefix}_max_args")
|
||||
|
||||
if { [ -n "$_min_args" ] && [ "$_min_args" -ne 1 ]; } || { [ -n "$_max_args" ] && [ "$_max_args" -ne 1 ]; }; then
|
||||
_err "Command #${_command_index} arg variable can only be used with commands that requires single argument."
|
||||
fi
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
_err "Command #${_command_index} arg variable cannot be empty."
|
||||
fi
|
||||
|
||||
if ! _is_valid_var_name "$1"; then
|
||||
_err "Command #${_command_index} arg variable is invalid: $1. Must be a valid variable name."
|
||||
fi
|
||||
|
||||
if ! _description=$(_is_free_var_name "$1"); then
|
||||
_err "Command #${_command_index} arg variable is already used. ${_description}"
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_option_aliases() {
|
||||
if [ -n "$(_var_value "${_mapping_option_prefix}_aliases")" ]; then
|
||||
_err "Option #${_option_index} aliases are already mapped."
|
||||
@@ -444,14 +671,9 @@ _validate_option_variable() {
|
||||
_err "Option #${_option_index} variable is invalid: $1. Must be a valid variable name."
|
||||
fi
|
||||
|
||||
_i=1
|
||||
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
|
||||
_err "Option #${_option_index} variable is already mapped for option #${_i}: $1."
|
||||
fi
|
||||
|
||||
_i=$(_math "$_i + 1")
|
||||
done
|
||||
if ! _description=$(_is_free_var_name "$1"); then
|
||||
_err "Option #${_option_index} variable is already used. ${_description}"
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_option_description() {
|
||||
@@ -477,10 +699,6 @@ _validate_option_max_args() {
|
||||
_err "Option #${_option_index} max args is invalid: $1. Must be a non-negative integer."
|
||||
fi
|
||||
|
||||
if [ -n "$(_var_value "${_mapping_option_prefix}_variable")" ] && [ "$1" -ne 1 ]; then
|
||||
_err "Option #${_option_index} max args is invalid: $1. Implicitly set to 1 when option variable was set."
|
||||
fi
|
||||
|
||||
if (_is "$(_var_value "${_mapping_option_prefix}_required")") && [ "$1" -eq 0 ]; then
|
||||
_err "Option #${_option_index} must be removed as constant. It is required without arguments."
|
||||
fi
|
||||
@@ -498,10 +716,6 @@ _validate_option_min_args() {
|
||||
if ! _is_int "$1"; then
|
||||
_err "Option #${_option_index} min args is invalid: $1. Must be a non-negative integer."
|
||||
fi
|
||||
|
||||
if [ -n "$(_var_value "${_mapping_option_prefix}_variable")" ] && [ "$1" -ne 1 ]; then
|
||||
_err "Option #${_option_index} min args is invalid: $1. Implicitly set to 1 when option variable was set."
|
||||
fi
|
||||
}
|
||||
|
||||
_validate_option_required() {
|
||||
@@ -628,9 +842,9 @@ _parse() {
|
||||
|
||||
if [ "$_min_positional_args" -gt 0 ] && [ "$_positional_args_count" -lt "$_min_positional_args" ]; then
|
||||
if [ "$_used_command_index" -eq 0 ]; then
|
||||
_err "At least $_min_positional_args argument(s) required."
|
||||
_err "At least $_min_positional_args positional argument(s) required."
|
||||
else
|
||||
_err "At least $_min_positional_args argument(s) required for command: $(_var_value "_commands_${_used_command_index}_name")."
|
||||
_err "At least $_min_positional_args positional argument(s) required for command: $(_var_value "_commands_${_used_command_index}_name")."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -640,25 +854,36 @@ _parse_positional_args() {
|
||||
_err "Positional arguments must be placed before options: $1."
|
||||
fi
|
||||
|
||||
if [ -z "$_command_index" ]; then
|
||||
_max_args_count="$_default_max_positional_args"
|
||||
else
|
||||
_max_args_count=$(_var_value "_commands_${_command_index}_max_args")
|
||||
if [ -n "$_command_index" ]; then
|
||||
_max_args=$(_var_value "_commands_${_command_index}_max_args")
|
||||
_arg_variable="$(_var_value "_commands_${_command_index}_arg_variable")"
|
||||
fi
|
||||
|
||||
if [ -z "$_max_args" ]; then
|
||||
_max_args=$_default_max_positional_args
|
||||
fi
|
||||
|
||||
if [ -z "$_arg_variable" ]; then
|
||||
_arg_variable="$_default_positional_arg_variable"
|
||||
fi
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
_positional_arg_index=$(_math "$_positional_args_count + 1")
|
||||
|
||||
if [ -n "$_max_args_count" ] && [ "$_positional_arg_index" -gt "$_max_args_count" ]; then
|
||||
if [ -n "$_max_args" ] && [ "$_positional_arg_index" -gt "$_max_args" ]; then
|
||||
if [ -z "$_command_index" ]; then
|
||||
_err "Maximum $_max_args_count positional argument(s) allowed."
|
||||
_err "Maximum $_max_args positional argument(s) allowed."
|
||||
else
|
||||
_err "Maximum $_max_args_count positional argument(s) allowed for command: $(_var_value "_commands_${_command_index}_name")."
|
||||
_err "Maximum $_max_args positional argument(s) allowed for command: $(_var_value "_commands_${_command_index}_name")."
|
||||
fi
|
||||
fi
|
||||
|
||||
_assign "_positional_args_${_positional_arg_index}" "$1"
|
||||
_positional_args_count=$_positional_arg_index
|
||||
_assign "_positional_args_count" "$_positional_arg_index"
|
||||
|
||||
if [ -n "$_arg_variable" ]; then
|
||||
_assign "$_arg_variable" "$1"
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
@@ -782,6 +1007,24 @@ _is_used_command() {
|
||||
[ -n "$_command_index" ] && [ -n "$_used_command_index" ] && [ "$_command_index" -eq "$_used_command_index" ]
|
||||
}
|
||||
|
||||
_get_positional_args() {
|
||||
_delimiter=${1:-" "}
|
||||
|
||||
|
||||
if [ "$_positional_args_count" -gt "1" ]; then
|
||||
_positional_args=""
|
||||
|
||||
_i=1
|
||||
while [ "$_i" -le "$_positional_args_count" ]; do
|
||||
_positional_arg=$(_var_value "_positional_args_${_i}")
|
||||
_positional_args="${_positional_args}${_delimiter}${_positional_arg}"
|
||||
_i=$(_math "$_i + 1")
|
||||
done
|
||||
|
||||
echo "${_positional_args#"$_delimiter"}"
|
||||
fi
|
||||
}
|
||||
|
||||
_get_positional_args_count() {
|
||||
echo "$_positional_args_count"
|
||||
}
|
||||
@@ -805,6 +1048,25 @@ _is_used_option() {
|
||||
[ -n "$_option_index" ] && _is "$(_var_value "_options_${_option_index}_used")"
|
||||
}
|
||||
|
||||
_get_option_args() {
|
||||
_option_index=$(_get_mapped_option_index_by_alias "$1")
|
||||
_delimiter=${2:-" "}
|
||||
|
||||
_option_args=""
|
||||
if [ -n "$_option_index" ]; then
|
||||
_option_args_count=$(_var_value "_options_${_option_index}_args_count")
|
||||
|
||||
_i=1
|
||||
while [ "$_i" -le "$_option_args_count" ]; do
|
||||
_arg=$(_var_value "_options_${_option_index}_args_${_i}")
|
||||
_option_args="${_option_args}${_delimiter}${_arg}"
|
||||
_i=$(_math "$_i + 1")
|
||||
done
|
||||
|
||||
echo "${_option_args#"$_delimiter"}"
|
||||
fi
|
||||
}
|
||||
|
||||
_get_option_args_count() {
|
||||
_option_index=$(_get_mapped_option_index_by_alias "$1")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user