Last active 1740031897

Taken from b167d3ec4e4f94d246ebdc4bcfdfb6ac

args.sh Raw
1#!/usr/bin/env bash
2
3# Argument parser for bash scripts
4#
5# Author: Anthony Axenov (Антон Аксенов)
6# Version: 1.6
7# License: MIT
8# Description: https://git.axenov.dev/anthony/shell/src/branch/master/helpers/arg-parser
9
10#purpose Little helper to check if string matches PCRE
11#argument $1 - some string
12#argument $2 - regex
13#exitcode 0 - string valid
14#exitcode 1 - string is not valid
15grep_match() {
16 printf "%s" "$1" | grep -qE "$2" >/dev/null
17}
18
19#purpose Find short argument or its value
20#argument $1 - (string) argument (without leading dashes; only first letter will be processed)
21#argument $2 - (number) is it flag? 1 if is, otherwise 0 or nothing
22#argument $3 - (string) variable to return value into
23# (if not specified then it will be echo'ed in stdout)
24#returns (string) 1 (if $2 == 1), value (if correct and if $2 != 1) or nothing
25#usage To get value into var: arg v 0 myvar or myvalue=$(arg 'v')
26#usage To find flag into var: arg f 1 myvar or flag=$(arg 'f')
27#usage To echo value: arg v
28#usage To echo 1 if flag exists: arg f
29arg() {
30 [ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
31 local arg_name="${1:0:1}" # first character of argument name to find
32 local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
33 local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
34 local value= # initialize empty value to check if we found one later
35 local arg_found=0 # marker of found argument
36
37 for idx in "${!__RAW_ARGS__[@]}"; do # going through all args
38 local arg_search=${__RAW_ARGS__[idx]} # get current argument
39
40 # skip $arg_search if it starts with '--' or letter
41 grep_match "$arg_search" "^(\w|--)" && continue
42
43 # clear $arg_search from special and duplicate characters, e.g. 'fas-)dfs' will become 'fasd'
44 local arg_chars="$(printf "%s" "$arg_search" \
45 | tr -s "[$arg_search]" 2>/dev/null \
46 | tr -d "[:punct:][:blank:]" 2>/dev/null)"
47
48 # if $arg_name is not one of $arg_chars the skip it
49 grep_match "-$arg_name" "^-[$arg_chars]$" || continue
50 arg_found=1
51
52 # then return '1'|'0' back into $value if we need flag or next arg value otherwise
53 [ "$is_flag" = 1 ] && value=1 || value="${__RAW_ARGS__[idx+1]}"
54 break
55 done
56
57 [ "$is_flag" = 1 ] && [ -z "$value" ] && value=0;
58
59 # if value we found is empty or looks like another argument then exit with error message
60 if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
61 echo "ERROR: Argument '-$arg_name' must have correct value!" >&2 && exit 1
62 fi
63
64 # return '$value' back into $var_name (if exists) or echo in stdout
65 [ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
66}
67
68#purpose Find long argument or its value
69#argument $1 - argument (without leading dashes)
70#argument $2 - (number) is it flag? 1 if is, otherwise 0 or nothing
71#argument $3 - (string) variable to return value into
72# (if not specified then it will be echo'ed in stdout)
73#returns (string) 1 (if $2 == 1), value (if correct and if $2 != 1) or nothing
74#usage To get value into var: arg v 0 myvar or myvalue=$(arg 'v')
75#usage To find flag into var: arg f 1 myvar or flag=$(arg 'f')
76#usage To echo value: arg v
77#usage To echo 1 if flag exists: arg f
78argl() {
79 [ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
80 local arg_name="$1" # argument name to find
81 local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
82 local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
83 local value= # initialize empty value to check if we found one later
84 local arg_found=0 # marker of found argument
85
86 for idx in "${!__RAW_ARGS__[@]}"; do # going through all args
87 local arg_search="${__RAW_ARGS__[idx]}" # get current argument
88
89 if [ "$arg_search" = "--$arg_name" ]; then # if current arg begins with two dashes
90 # then return '1' back into $value if we need flag or next arg value otherwise
91 [ "$is_flag" = 1 ] && value=1 || value="${__RAW_ARGS__[idx+1]}"
92 break # stop the loop
93 elif grep_match "$arg_search" "^--$arg_name=.+$"; then # check if $arg like '--foo=bar'
94 # then return '1' back into $value if we need flag or part from '=' to arg's end as value otherwise
95 [ "$is_flag" = 1 ] && value=1 || value="${arg_search#*=}"
96 break # stop the loop
97 fi
98 done
99
100 [ "$is_flag" = 1 ] && [ -z "$value" ] && value=0;
101
102 # if value we found is empty or looks like another argument then exit with error message
103 if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
104 echo "ERROR: Argument '--$arg_name' must have correct value!" >&2 && exit 1;
105 fi
106
107 # return '$value' back into $var_name (if exists) or echo in stdout
108 [ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
109}
110
111################################
112
113# This is simple examples which you can play around with.
114# 1. uncomment code below
115# 2. call thi sscript to see what happens:
116# /args.sh -abcd --flag1 --flag2 -e evalue -f fvalue --arg1=value1 --arg2 value2
117
118# __RAW_ARGS__=("$@")
119
120# arg a 1 flag_a
121# echo "Flag -a has value '$flag_a'"
122# echo "Flag -a has value '$(arg a 1)'"
123
124# arg b 1 flag_b
125# echo "Flag -b has value '$flag_b'"
126# echo "Flag -b has value '$(arg b 1)'"
127
128# arg c 1 flag_c
129# echo "Flag -c has value '$flag_c'"
130# echo "Flag -c has value '$(arg c 1)'"
131
132# arg d 1 flag_d
133# echo "Flag -d has value '$flag_d'"
134# echo "Flag -d has value '$(arg d 1)'"
135
136# argl flag1 1 flag_1
137# echo "Flag --flag1 has value '$flag_1'"
138# echo "Flag --flag1 has value '$(argl flag1 1)'"
139
140# argl flag2 1 flag_2
141# echo "Flag --flag2 has value '$flag_2'"
142# echo "Flag --flag2 has value '$(argl flag2 1)'"
143
144# arg e 0 arg_e
145# echo "Arg -e has value '$arg_e'"
146# echo "Arg -e has value '$(arg e 0)'"
147
148# arg f 0 arg_f
149# echo "Arg -f has value '$arg_f'"
150# echo "Arg -f has value '$(arg f 0)'"
151
152# argl arg1 0 arg_1
153# echo "Arg --arg1 has value '$arg_1'"
154# echo "Arg --arg1 has value '$(argl arg1 0)'"
155
156# argl arg2 0 arg_2
157# echo "Arg --arg2 has value '$arg_2'"
158# echo "Arg --arg2 has value '$(argl arg2 0)'"