You've already forked sh-args-parser
mirror of
https://github.com/nikolaypronchev/sh-args-parser.git
synced 2026-04-23 16:46:30 +03:00
Compare commits
2 Commits
6887a39f03
...
4e979574d8
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e979574d8 | |||
| 5f3b3c693f |
41
README.md
41
README.md
@@ -71,7 +71,7 @@ A command typically represents the core action performed by the script: `run`, `
|
|||||||
|
|
||||||
- Positional arguments are placed after the command, if present.
|
- Positional arguments are placed after the command, if present.
|
||||||
- The presence and number of positional arguments are determined by the script's logic.
|
- 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
|
||||||
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`.
|
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,31 +83,32 @@ Options are script parameters. Each option has at least one alias by which it ca
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Configuration is defined by assigning values to variables before using the parser. For example:
|
Configuration is done by assigning values to special keys via [`_set_config`](#_set_config) before using [`_parse`](#_parse).
|
||||||
|
|
||||||
```bash
|
|
||||||
_accept_command=true
|
|
||||||
```
|
|
||||||
Configuration variables must be assigned before calling `_parse`.
|
|
||||||
|
|
||||||
| Name | Default Value | Description |
|
| 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_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. |
|
| 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_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_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. |
|
| 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)). |
|
| 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)). |
|
| 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_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_key_value_delimiter | `' '` | Option alias-args delimiter. Allowed values: `' '` `=` `:`.|
|
||||||
| _option_values_delimiter | `' '` | Option values delimiter. |
|
| 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_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. |
|
| 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. |
|
| 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
|
## Functions
|
||||||
|
|
||||||
|
#### _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
|
#### _parse
|
||||||
Parses the provided arguments. Typically, takes all command-line arguments `$@` as input.
|
Parses the provided arguments. Typically, takes all command-line arguments `$@` as input.
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
182
parser.sh
182
parser.sh
@@ -52,6 +52,10 @@ _is_int() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_is_flag() {
|
||||||
|
[ "$1" = "true" ] || [ "$1" = "false" ]
|
||||||
|
}
|
||||||
|
|
||||||
_assign() {
|
_assign() {
|
||||||
if ! _is_valid_var_name "$1"; then
|
if ! _is_valid_var_name "$1"; then
|
||||||
_err "Invalid variable name: $1."
|
_err "Invalid variable name: $1."
|
||||||
@@ -154,14 +158,14 @@ _mapped_options_only() {
|
|||||||
|
|
||||||
_is_free_var_name() {
|
_is_free_var_name() {
|
||||||
if [ -n "$_default_positional_arg_variable" ] && [ "$_default_positional_arg_variable" = "$1" ]; then
|
if [ -n "$_default_positional_arg_variable" ] && [ "$_default_positional_arg_variable" = "$1" ]; then
|
||||||
echo "variable is already used as default positional arg variable: $1."
|
echo "Variable is already used as default positional arg variable: $1."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_i=1
|
_i=1
|
||||||
while [ "$_i" -le "$_mapped_options_count" ]; do
|
while [ "$_i" -le "$_mapped_options_count" ]; do
|
||||||
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
|
if [ "$1" = "$(_var_value "_options_${_i}_variable")" ]; then
|
||||||
echo "variable is already mapped for option #${_i}: $1."
|
echo "Variable is already mapped for option #${_i}: $1."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -171,7 +175,7 @@ _is_free_var_name() {
|
|||||||
_i=1
|
_i=1
|
||||||
while [ "$_i" -le "$_mapped_commands_count" ]; do
|
while [ "$_i" -le "$_mapped_commands_count" ]; do
|
||||||
if [ "$1" = "$(_var_value "_commands_${_i}_arg_variable")" ]; then
|
if [ "$1" = "$(_var_value "_commands_${_i}_arg_variable")" ]; then
|
||||||
echo "arg variable is already mapped for command #${_i}: $1."
|
echo "Arg variable is already mapped for command #${_i}: $1."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -179,6 +183,45 @@ _is_free_var_name() {
|
|||||||
done
|
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() {
|
_map_command() {
|
||||||
_command_index=$(_math "$_mapped_commands_count + 1")
|
_command_index=$(_math "$_mapped_commands_count + 1")
|
||||||
_mapping_command_prefix="_commands_${_command_index}"
|
_mapping_command_prefix="_commands_${_command_index}"
|
||||||
@@ -306,6 +349,131 @@ _map_option_auto() {
|
|||||||
_mapped_options_count=$_option_index
|
_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() {
|
_validate_command_description() {
|
||||||
if [ -n "$(_var_value "${_mapping_command_prefix}_description")" ]; then
|
if [ -n "$(_var_value "${_mapping_command_prefix}_description")" ]; then
|
||||||
@@ -400,7 +568,7 @@ _validate_command_arg_variable() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! _description=$(_is_free_var_name "$1"); then
|
if ! _description=$(_is_free_var_name "$1"); then
|
||||||
_err "Command #${_command_index} ${_description}"
|
_err "Command #${_command_index} arg variable is already used. ${_description}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +672,7 @@ _validate_option_variable() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! _description=$(_is_free_var_name "$1"); then
|
if ! _description=$(_is_free_var_name "$1"); then
|
||||||
_err "Option #${_option_index} ${_description}"
|
_err "Option #${_option_index} variable is already used. ${_description}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,9 +842,9 @@ _parse() {
|
|||||||
|
|
||||||
if [ "$_min_positional_args" -gt 0 ] && [ "$_positional_args_count" -lt "$_min_positional_args" ]; then
|
if [ "$_min_positional_args" -gt 0 ] && [ "$_positional_args_count" -lt "$_min_positional_args" ]; then
|
||||||
if [ "$_used_command_index" -eq 0 ]; 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
|
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
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user