159 lines
6.4 KiB
Bash
Executable File
159 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Argument parser for bash scripts
|
|
#
|
|
# Author: Anthony Axenov (Антон Аксенов)
|
|
# Version: 1.6
|
|
# License: MIT
|
|
# Description: https://git.axenov.dev/anthony/shell/src/branch/master/helpers/arg-parser
|
|
|
|
#purpose Little helper to check if string matches PCRE
|
|
#argument $1 - some string
|
|
#argument $2 - regex
|
|
#exitcode 0 - string valid
|
|
#exitcode 1 - string is not valid
|
|
grep_match() {
|
|
printf "%s" "$1" | grep -qE "$2" >/dev/null
|
|
}
|
|
|
|
#purpose Find short argument or its value
|
|
#argument $1 - (string) argument (without leading dashes; only first letter will be processed)
|
|
#argument $2 - (number) is it flag? 1 if is, otherwise 0 or nothing
|
|
#argument $3 - (string) variable to return value into
|
|
# (if not specified then it will be echo'ed in stdout)
|
|
#returns (string) 1 (if $2 == 1), value (if correct and if $2 != 1) or nothing
|
|
#usage To get value into var: arg v 0 myvar or myvalue=$(arg 'v')
|
|
#usage To find flag into var: arg f 1 myvar or flag=$(arg 'f')
|
|
#usage To echo value: arg v
|
|
#usage To echo 1 if flag exists: arg f
|
|
arg() {
|
|
[ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
|
|
local arg_name="${1:0:1}" # first character of argument name to find
|
|
local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
|
|
local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
|
|
local value= # initialize empty value to check if we found one later
|
|
local arg_found=0 # marker of found argument
|
|
|
|
for idx in "${!__RAW_ARGS__[@]}"; do # going through all args
|
|
local arg_search=${__RAW_ARGS__[idx]} # get current argument
|
|
|
|
# skip $arg_search if it starts with '--' or letter
|
|
grep_match "$arg_search" "^(\w|--)" && continue
|
|
|
|
# clear $arg_search from special and duplicate characters, e.g. 'fas-)dfs' will become 'fasd'
|
|
local arg_chars="$(printf "%s" "$arg_search" \
|
|
| tr -s "[$arg_search]" 2>&1 >/dev/null \
|
|
| tr -d "[:punct:][:blank:]" 2>&1 >/dev/null)"
|
|
|
|
# if $arg_name is not one of $arg_chars the skip it
|
|
grep_match "-$arg_name" "^-[$arg_chars]$" || continue
|
|
arg_found=1
|
|
|
|
# then return '1'|'0' back into $value if we need flag or next arg value otherwise
|
|
[ "$is_flag" = 1 ] && value=1 || value="${__RAW_ARGS__[idx+1]}"
|
|
break
|
|
done
|
|
|
|
[ "$is_flag" = 1 ] && [ -z "$value" ] && value=0;
|
|
|
|
# if value we found is empty or looks like another argument then exit with error message
|
|
if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
|
|
echo "ERROR: Argument '-$arg_name' must have correct value!" >&2 && exit 1
|
|
fi
|
|
|
|
# return '$value' back into $var_name (if exists) or echo in stdout
|
|
[ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
|
|
}
|
|
|
|
#purpose Find long argument or its value
|
|
#argument $1 - argument (without leading dashes)
|
|
#argument $2 - (number) is it flag? 1 if is, otherwise 0 or nothing
|
|
#argument $3 - (string) variable to return value into
|
|
# (if not specified then it will be echo'ed in stdout)
|
|
#returns (string) 1 (if $2 == 1), value (if correct and if $2 != 1) or nothing
|
|
#usage To get value into var: arg v 0 myvar or myvalue=$(arg 'v')
|
|
#usage To find flag into var: arg f 1 myvar or flag=$(arg 'f')
|
|
#usage To echo value: arg v
|
|
#usage To echo 1 if flag exists: arg f
|
|
argl() {
|
|
[ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
|
|
local arg_name="$1" # argument name to find
|
|
local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
|
|
local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
|
|
local value= # initialize empty value to check if we found one later
|
|
local arg_found=0 # marker of found argument
|
|
|
|
for idx in "${!__RAW_ARGS__[@]}"; do # going through all args
|
|
local arg_search="${__RAW_ARGS__[idx]}" # get current argument
|
|
|
|
if [ "$arg_search" = "--$arg_name" ]; then # if current arg begins with two dashes
|
|
# then return '1' back into $value if we need flag or next arg value otherwise
|
|
[ "$is_flag" = 1 ] && value=1 || value="${__RAW_ARGS__[idx+1]}"
|
|
break # stop the loop
|
|
elif grep_match "$arg_search" "^--$arg_name=.+$"; then # check if $arg like '--foo=bar'
|
|
# then return '1' back into $value if we need flag or part from '=' to arg's end as value otherwise
|
|
[ "$is_flag" = 1 ] && value=1 || value="${arg_search#*=}"
|
|
break # stop the loop
|
|
fi
|
|
done
|
|
|
|
[ "$is_flag" = 1 ] && [ -z "$value" ] && value=0;
|
|
|
|
# if value we found is empty or looks like another argument then exit with error message
|
|
if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
|
|
echo "ERROR: Argument '--$arg_name' must have correct value!" >&2 && exit 1;
|
|
fi
|
|
|
|
# return '$value' back into $var_name (if exists) or echo in stdout
|
|
[ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
|
|
}
|
|
|
|
################################
|
|
|
|
# This is simple examples which you can play around with.
|
|
# 1. uncomment code below
|
|
# 2. call thi sscript to see what happens:
|
|
# /args.sh -abcd --flag1 --flag2 -e evalue -f fvalue --arg1=value1 --arg2 value2
|
|
|
|
# __RAW_ARGS__=("$@")
|
|
|
|
# arg a 1 flag_a
|
|
# echo "Flag -a has value '$flag_a'"
|
|
# echo "Flag -a has value '$(arg a 1)'"
|
|
|
|
# arg b 1 flag_b
|
|
# echo "Flag -b has value '$flag_b'"
|
|
# echo "Flag -b has value '$(arg b 1)'"
|
|
|
|
# arg c 1 flag_c
|
|
# echo "Flag -c has value '$flag_c'"
|
|
# echo "Flag -c has value '$(arg c 1)'"
|
|
|
|
# arg d 1 flag_d
|
|
# echo "Flag -d has value '$flag_d'"
|
|
# echo "Flag -d has value '$(arg d 1)'"
|
|
|
|
# argl flag1 1 flag_1
|
|
# echo "Flag --flag1 has value '$flag_1'"
|
|
# echo "Flag --flag1 has value '$(argl flag1 1)'"
|
|
|
|
# argl flag2 1 flag_2
|
|
# echo "Flag --flag2 has value '$flag_2'"
|
|
# echo "Flag --flag2 has value '$(argl flag2 1)'"
|
|
|
|
# arg e 0 arg_e
|
|
# echo "Arg -e has value '$arg_e'"
|
|
# echo "Arg -e has value '$(arg e 0)'"
|
|
|
|
# arg f 0 arg_f
|
|
# echo "Arg -f has value '$arg_f'"
|
|
# echo "Arg -f has value '$(arg f 0)'"
|
|
|
|
# argl arg1 0 arg_1
|
|
# echo "Arg --arg1 has value '$arg_1'"
|
|
# echo "Arg --arg1 has value '$(argl arg1 0)'"
|
|
|
|
# argl arg2 0 arg_2
|
|
# echo "Arg --arg2 has value '$arg_2'"
|
|
# echo "Arg --arg2 has value '$(argl arg2 0)'"
|