Skip to content

Commit 49bb2c1

Browse files
committed
Merge branch 'develop'
2 parents ce9366d + 0048047 commit 49bb2c1

File tree

2 files changed

+180
-64
lines changed

2 files changed

+180
-64
lines changed

README.md

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,48 @@ Takes arguments passed in nearly any format to a bash script and allows easy acc
44

55
## Use
66

7+
### How To Use
8+
9+
Just include the library in the head of script, define all the arguments you need and call the parser function
10+
11+
```bash
12+
# Include the Argument Parser library
13+
source ./my/lib/path/argument-parser.sh
14+
15+
# Define the expected arguments
16+
argExpected['test']="argName - This is a short description of the argument and what it does"
17+
argExpected['R']="secondArgName - This is another argument that can be passed"
18+
19+
# Parse any arguments
20+
argParse
21+
```
22+
23+
### Defining Expected Arguments
24+
25+
The argument parser can take an array of arguments to expect, it has the following format:
26+
27+
```bash
28+
# Define the -r argument
29+
argExpected['r']="argumentName - Argument description"
30+
31+
# Define the --test argument
32+
argExpected['test']="argumentName - Argument description"
33+
34+
# Define both the -u and --uniform arguments
35+
argExpected['u|uniform']="argumentName - Argument description"
36+
37+
# Define both the -a and -A arguments
38+
argExpected['a|A']="argumentName - Argument description"
39+
40+
# Define the -d, --deamon and -D arguments
41+
argExpected['d|deamon|D']="argumentName - Argument description"
42+
```
43+
44+
The `argumentName` part of the definition is the name given to the argument and what should be passed to the `argValue` and `argExists` functions, see below.
45+
46+
By default if an argument is passed that hasn't been defined an error will be thrown and the script will exit.
47+
This feature can be turned off by setting `ARG_MUST_BE_DEFINED` to `false`, note that the argument names will default to the argument its self, without the preceding hyphen(s).
48+
749
### Get An Arguments Value
850

951
There is a helper function named `argValue()` which takes the name of
@@ -128,9 +170,9 @@ The order the arguments are passed on the command line makes a difference
128170

129171
* Calling `my-script.sh -f first -f last` will cause `argValue "f"` to return the value `last`
130172
* Calling `my-script.sh -g 345 -g` will mean cause `argValue "g"` to return nothing
131-
* Calling `my-script.sh --size 512 --size=1024` will mean cause `argValue "size"` to return 1024
173+
* Calling `my-script.sh --size 512 --size=1024` will mean cause `argValue "size"` to return `1024`
132174

133175
## Debug Mode
134176

135-
There is a debug mode that can be enabled by setting the `ARG_DEBUG` variable at the top of the script to `true`.
177+
There is a debug mode that can be enabled by setting the `ARG_DEBUG` variable to `true` right before calling `argParse`.
136178
This will cause the script to dump out information about which flags it finds and of what kind etc

argument-parser.sh

Lines changed: 136 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ regexArgLongWithValue='^--([a-zA-Z0-9\-]{2,})=(.*)$'
88

99
argChunks=()
1010

11-
ARG_DEBUG=false
12-
1311
# Expand chained short form arguments, eg -aih => -a -i -h
1412
for argChunk in "$@"; do
1513

@@ -39,77 +37,45 @@ for argChunk in "$@"; do
3937
argChunks+=("$argChunk")
4038
done
4139

42-
[ $ARG_DEBUG == true ] && echo "Expanded argument list: ${argChunks[@]}"
40+
[ "$ARG_DEBUG" == true ] && echo "Expanded argument list: ${argChunks[@]}"
4341

4442
# Initialise some variables
4543
declare -A argv
4644
lastWasArgument=0
4745
lastArgument=""
4846

49-
# Loop over all the argument chunks and determine if the argument type and value
50-
for argChunk in "${argChunks[@]}"; do
51-
52-
# Check if this chunk is a short form argument
53-
[[ $argChunk =~ $regexArgShort ]]
54-
if [ "${BASH_REMATCH[1]}" != "" ]; then
55-
argument="${BASH_REMATCH[1]}"
56-
lastWasArgument=1
57-
lastArgument="$argument"
58-
59-
# Add the argument to the arguments array
60-
argv["${BASH_REMATCH[1]}"]=''
61-
62-
[ $ARG_DEBUG == true ] && echo "Argument (short): ${BASH_REMATCH[1]}"
63-
64-
continue;
65-
fi
66-
67-
# Check if this chunk is a long form with value argument
68-
[[ $argChunk =~ $regexArgLongWithValue ]]
69-
if [ "${BASH_REMATCH[1]}" != "" ]; then
70-
argument="${BASH_REMATCH[1]}"
71-
lastArgument="$argument"
72-
73-
# Add the argument to the arguments array
74-
argv["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
75-
76-
[ $ARG_DEBUG == true ] && echo "Argument (long with value): ${BASH_REMATCH[1]}=${BASH_REMATCH[2]}"
77-
78-
continue;
79-
fi
47+
declare -A argExpected
8048

81-
# Check if this chunk is a long form argument
82-
[[ $argChunk =~ $regexArgLong ]]
83-
if [ "${BASH_REMATCH[1]}" != "" ]; then
84-
argument="${BASH_REMATCH[1]}"
85-
lastWasArgument=1
86-
lastArgument="$argument"
49+
argGetName() {
50+
for k in "${!argExpected[@]}"
51+
do
52+
regexArg="\|($1)\|"
53+
[[ "|$k|" =~ $regexArg ]]
54+
if [ "${BASH_REMATCH[1]}" != "" ]; then
8755

88-
# Add the argument to the arguments array
89-
argv["${BASH_REMATCH[1]}"]=''
56+
regexArgName="(.+) - "
57+
[[ "${argExpected[$k]}" =~ $regexArgName ]]
9058

91-
[ $ARG_DEBUG == true ] && echo "Argument (long): ${BASH_REMATCH[1]}"
59+
echo "${BASH_REMATCH[1]}"
60+
exit 0
61+
fi
62+
done
9263

93-
continue;
64+
# Check if the argument must be defined
65+
if [ "$ARG_MUST_BE_DEFINED" != false ]; then
66+
argUnexpected "$argChunk"
67+
exit 2
9468
fi
9569

96-
# If the last chunk was an argument and this wasn't assume its an argument value
97-
if [ $lastWasArgument == 1 ]; then
70+
# Default to using the argument as the name
71+
echo "$1"
9872

99-
# Add the arguments value to the arguments array
100-
argv["$lastArgument"]="$argChunk"
101-
102-
[ $ARG_DEBUG == true ] && echo "Argument Value: $argChunk"
103-
104-
lastWasArgument=0
105-
fi
106-
done
73+
exit 1
74+
}
10775

108-
[ $ARG_DEBUG == true ] && echo "Argument array:"
109-
[ $ARG_DEBUG == true ] && for k in "${!argv[@]}"
110-
do
111-
echo "ARG: $k = ${argv[$k]}"
112-
done
76+
argUnexpected() {
77+
echo "UNEXPECTED ARGUMENT $1"
78+
}
11379

11480
argExists() {
11581
if [ -z ${argv["$1"]+abc} ]; then
@@ -125,7 +91,115 @@ argValue() {
12591
fi
12692
}
12793

128-
# Add the standard argc variable containing the number of arguments
129-
argc=${#argv[@]}
94+
argParse() {
95+
# Loop over all the argument chunks and determine if the argument type and value
96+
for argChunk in "${argChunks[@]}"; do
97+
98+
# Check if this chunk is a short form argument
99+
[[ $argChunk =~ $regexArgShort ]]
100+
if [ "${BASH_REMATCH[1]}" != "" ]; then
101+
argument="${BASH_REMATCH[1]}"
102+
lastWasArgument=1
103+
lastArgument="$argument"
104+
105+
# Get the name of the argument
106+
argName="$(argGetName "$argument")"
107+
108+
# Check we could get an argument, return code 2 means an error was returned
109+
if [ "$?" == "2" ]; then
110+
echo "$argName"
111+
exit 1
112+
fi
113+
114+
# Add the argument to the arguments array
115+
argv["$argName"]=''
116+
117+
[ "$ARG_DEBUG" == true ] && echo "Argument (short): ${BASH_REMATCH[1]}"
118+
119+
continue;
120+
fi
121+
122+
# Check if this chunk is a long form with value argument
123+
[[ $argChunk =~ $regexArgLongWithValue ]]
124+
if [ "${BASH_REMATCH[1]}" != "" ]; then
125+
argument="${BASH_REMATCH[1]}"
126+
lastArgument="$argument"
127+
128+
# Get the name of the argument
129+
argName="$(argGetName "$argument")"
130+
131+
# Check we could get an argument, return code 2 means an error was returned
132+
if [ "$?" == "2" ]; then
133+
echo "$argName"
134+
exit 1
135+
fi
136+
137+
# Add the argument to the arguments array
138+
argv["$argName"]="${BASH_REMATCH[2]}"
139+
140+
[ "$ARG_DEBUG" == true ] && echo "Argument (long with value): ${BASH_REMATCH[1]}=${BASH_REMATCH[2]}"
141+
142+
continue;
143+
fi
144+
145+
# Check if this chunk is a long form argument
146+
[[ $argChunk =~ $regexArgLong ]]
147+
if [ "${BASH_REMATCH[1]}" != "" ]; then
148+
argument="${BASH_REMATCH[1]}"
149+
lastWasArgument=1
150+
lastArgument="$argument"
151+
152+
# Get the name of the argument
153+
argName="$(argGetName "$argument")"
154+
155+
# Check we could get an argument, return code 2 means an error was returned
156+
if [ "$?" == "2" ]; then
157+
echo "$argName"
158+
exit 1
159+
fi
160+
161+
# Add the argument to the arguments array
162+
argv["$argName"]=''
163+
164+
[ "$ARG_DEBUG" == true ] && echo "Argument (long): ${BASH_REMATCH[1]}"
165+
166+
continue;
167+
fi
168+
169+
# If the last chunk was an argument and this wasn't assume its an argument value
170+
if [ $lastWasArgument == 1 ]; then
171+
172+
# Get the name of the argument
173+
argName="$(argGetName "$lastArgument")"
174+
175+
# Check we could get an argument, return code 2 means an error was returned
176+
if [ "$?" == "2" ]; then
177+
echo "$argName"
178+
exit 1
179+
fi
180+
181+
# Add the arguments value to the arguments array
182+
argv["$argName"]="$argChunk"
183+
184+
[ "$ARG_DEBUG" == true ] && echo "Argument Value: $argChunk"
185+
186+
lastWasArgument=0
187+
fi
188+
done
189+
190+
[ "$ARG_DEBUG" == true ] && echo "Argument array:"
191+
[ "$ARG_DEBUG" == true ] && for k in "${!argv[@]}"
192+
do
193+
echo "ARG: $k = ${argv[$k]}"
194+
done
195+
196+
# Add the standard argc variable containing the number of arguments
197+
argc=${#argv[@]}
198+
199+
[ "$ARG_DEBUG" == true ] && echo "Argument Count: $argc"
200+
}
130201

131-
[ $ARG_DEBUG == true ] && echo "Argument Count: $argc"
202+
# If we are accessing this script directly run the argument parser, useful for testing
203+
if [ "$0" == "$BASH_SOURCE" ]; then
204+
argParse
205+
fi

0 commit comments

Comments
 (0)