Command line arguments in shell script - shell

Following is the shell script which iterates over command line arguments and prints the values
for var in "$#"
do
echo $var
done
Now if i want to iterate from the second command line argument (the first argument being used for some other purpose), what is the command to exclude the first argument alone in iteration ?

Use shift:
#!/usr/bin/env bash
shift
for var in "$#"; do
echo "$var"
done

The first argument is in $1, so doing
var1=$1
will store it into var1
You can then use shift to "delete" the first arg and still use your for loop:
~$cat s.sh
var1=$1
shift
echo var1=$var1
for var in "$#"
do
echo $var
done
~$ ./s.sh 1 2 3
var1=1
2
3
From man bash:
shift [n]
The positional parameters from n+1 ... are renamed to $1 .... Parameters
represented by the numbers $# down to $#-n+1 are unset. n
must be a non-negative number less than or equal to $#. If n
is 0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters
are not changed. The return status is greater than zero if n is
greater than $# or less than zero; otherwise 0.

This example behaves more like a standard unix command line utility. Options are processed in any order and can have modifiers. It does not work for every situation (like modifiers with spaces in them), but I've found it to be very useful for scripts that I want to have some default behavior, but occasionally I want to modify one or more parameters.
#!/bin/bash
#defaults
VAR1="Yours"
VAR2="Mine"
VAR3="Ours"
SHARENICE="false"
while [ $# -gt 0 ]; do
case "$1" in
#single parameter
-s) SHARENICE="true"
shift
;;
#modified parameters
-1) VAR1="$2"
shift 2
;;
-2) VAR2="$2"
shift 2
;;
-3) VAR3="$2"
shift 2
;;
#you could put a 'usage' function here,
#or if your last parameter has no modifier,
#like a mandatory input, it will now be at
#$1
*)
break
;;
esac
done
echo -n "$VAR1, $VAR2 and $VAR3. "
if [ "$SHARENICE" != "true" ]; then
echo "Too bad we don't get along."
else
echo "Good thing we play nice!"
fi

Related

Determining if there is a next argument while iterating through the arguments

While iterating through the arguments, how do you determine if there is a next argument?
The way I tried to approach this was to check if the next argument is not empty but I ran into some problems.
Here in this example I print the value of the current argument and if there is an argument that comes after that then print some message.
My approach:
use $i+1 where $i+1 will give you the value of the next index.
#!/bin/sh
for i in "$#"
do
echo $i
if ! [ ${i+1}="" ]; then
echo "test"
fi
done
sh test 1 2 3 4 5
but that didn't work. I also tried expr i + 1, but that didn't work as well.
If anyone could give me a hint on how to approach this problem that would be really appreciated.
#!/bin/sh
while [ $# -gt 0 ] ; do
echo $1
if [ -n "${2+x}" ]; then
echo another arg follows
fi
shift
done
$ ./test.sh 1 2 3
1
another arg follows
2
another arg follows
3
The trick here is that we use shift for consuming the argument list instead of iterating over it. The next argument is always $1, which we know exists because we only execute the loop if $# (the count of the positional arguments, not including $0) is positive. To check whether the argument after that, $2, exist, we can use the ${PARAM+WORD} expansion, which produces nothing if PARAM doesn't exist, otherwise produces WORD.
Of course, shift destroys the argument list. If you don't want that, move things into a function. The following example shows how we can process the same argument list twice by passing a copy into a function in which shift locally eats it:
#!/bin/sh
func() {
while [ $# -gt 0 ] ; do
echo $1
if [ -n "${2+x}" ]; then
echo another arg follows
fi
shift
done
}
func "$#"
func "$#"
$ ./test.sh 1 2 3
1
another arg follows
2
another arg follows
3
1
another arg follows
2
another arg follows
3
You can use a counter and check for $#:
n=1
for i in "$#"; do
echo "$i"
if [ $n -eq $# ]; then
echo "test"
fi
n=$(expr $n + 1)
done

bash argument case for args in $#

I have a script with a long list of OPTIONAL arguments. some have associated values.
Such as:
.script --first 2012-12-25 --last 2012-12-26 --copy --remove
.script --first 2012-12-25
Thus the following case statement:
for arg in "$#"
do
case $arg in
"--first" )
START_DATE=$arg;;
"--last" )
END_DATE=$arg;;
"--copy" )
COPY=true;;
"--remove" )
REMOVE=true;;
# ... and so on
esac
done
My problem:
that needs a increment $arg+1 type statement to get the following arg (in some cases).
How is that possible?
I'm also happy to do a substring such .script --first2012-12-25 --last2012-12-26
and not sure how to proceed there.
You can allow both --a=arg or -a arg options with a little more work:
START_DATE="$(date '+%Y-%m-%d')";
LAST_DATE="$(date '+%Y-%m-%d')";
while [[ $# -gt 0 ]] && [[ "$1" == "--"* ]] ;
do
opt="$1";
shift; #expose next argument
case "$opt" in
"--" ) break 2;;
"--first" )
START_DATE="$1"; shift;;
"--first="* ) # alternate format: --first=date
START_DATE="${opt#*=}";;
"--last" )
LAST_DATE="$1"; shift;;
"--last="* )
LAST_DATE="${opt#*=}";;
"--copy" )
COPY=true;;
"--remove" )
REMOVE=true;;
"--optional" )
OPTIONAL="$optional_default";; #set to some default value
"--optional=*" )
OPTIONAL="${opt#*=}";; #take argument
*) echo >&2 "Invalid option: $#"; exit 1;;
esac
done
Note the --optional argument uses a default value if "=" is not used, else it sets the value in the normal way.
Use shift in the end of each case statement.
Quote from a bash manual:
shift [n]
The positional parameters from n+1 ... are renamed to $1
.... Parameters represented by the numbers $# down to $#-n+1 are
unset. n must be a non-negative number less than or equal to $#. If
n is 0, no parameters are changed. If n is not given, it is assumed
to be 1. If n is greater than $#, the positional parameters are not
changed. The return status is greater than zero if n is greater than
$# or less than zero; otherwise 0.
$# is an array, & not a simple variable.
You can capture it to a local variable as x=("$#") & then use array x with indices as 0 to ($# - 1).
To access individual elements, use ${x[$i]}. You can NOT directly use ${#[$i]}, however.
So instead of for arg in "$#" loop, you will have i=0; while [ $i -lt $# ]; do loop.
If you have more than one option, and especially options with values mixed with options without values, let getopts do the work for you.
getopts cannot have optional arguments it seems. otherwise great.
my solution
loop the $# and setting a variable equal to x=$arg
do the case switch on that variable (rather than arg)
that worked fine for arguments of the type --startdate 2012-12-25 --enddate 2012-12-29
but did not work for --remove that has no following argument.
therefore tack on stuff (unlikely argument) onto the arg string.
leaving the following
argc="$# jabberwhocky"
echo $argc
x=0
# x=0 for unset variable
for arg in $argc
do
case $x in
"--start" )
STARTDATE=$arg ;;
"--end" )
ENDDATE=$arg ;;
"--copy" )
COPY=true;;
"--remove" )
REMOVE=true;;
... and so on....
esac
x=$arg
done

Understanding parameters in a function

I found this function:
findsit()
{
OPTIND=1
local case=""
local usage="findsit: find string in files.
Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
while getopts :it opt
do
case "$opt" in
i) case="-i " ;;
*) echo "$usage"; return;;
esac
done
shift $(( $OPTIND - 1 ))
if [ "$#" -lt 1 ]; then
echo "$usage"
return;
fi
find . -type f -name "${2:-*}" -print0 | \
xargs -0 egrep --color=always -sn ${case} "$1" 2>&- | more
}
I understand the output and what it does, but there are some terms I still don't understand and find it hard to find a reference, but believe they would be useful to learn in my programming. Can anyone quickly explain them? Some don't have man pages.
local
getopts
case
shift
$#
${2:-*}
2>&-
Thank you.
local: Local variable. Let's say you had a variable called foo in your program. You call a function that also has a variable foo. Let's say the function changes the value of foo.
Try this program:
testme()
{
foo="barfoo"
echo "In function: $foo"
}
foo="bar"
echo "In program: $foo"
testme
echo "After function in program: $foo"
Notice that the value of $foo has been changed by the function even after the function has completed. By declaring local foo="barfoo" instead of just foo="barfoo", we could have prevented this from happening.
case: A case statement is a way of specifying a list of options and what you want to do with each of those options. It is sort of like an if/then/else statement.
These two are more or less equivelent:
if [[ "$foo" == "bar" ]]
then
echo "He said 'bar'!"
elif [[ "$foo" == "foo" ]]
then
echo "Don't repeat yourself!"
elif [[ "$foo" == "foobar" ]]
then
echo "Shouldn't it be 'fubar'?"
else
echo "You didn't put anything I understand"
fi
and
case $foo in
bar)
echo "He said 'bar'!"
;;
foo)
echo "Don't repeat yourself!"
;;
foobar)
echo "Shouldn't it be 'fubar'?"
;;
*)
echo "You didn't put anything I understand"
;;
esac
The ;; ends the case option. Otherwise, it'll drop down to the next one and execute those lines too. I have each option in three lines, but they're normally combined like
foobar) echo "Shouldn't it be 'fubar'?";;
shift: The command line arguments are put in the variable called $*. When you say shift, it takes the first value in that $* variable, and deletes it.
getopts: Getopts is a rather complex command. It's used to parse the value of single letter options in the $# variable (which contains the parameters and arguments from the command line). Normally, you employ getopts in a while loop and use case statement to parse the output. The format is getopts <options> var. The var is the variable that will contain each option one at a time. The specify the single letter parameters and which ones require an argument. The best way to explain it is to show you a simple example.
$#: The number of parameters/arguments on the command line.
${var:-alternative}: This says to use the value of the environment variable $var. However, if this environment variable is not set or is null, use the value alternative instead. In this program ${2:-*} is used instead. The $2 represents the second parameter of what's left in the command line parameters/arguments after everything has been shifted out due to the shift command.
2>&-: This moves Standard Error to Standard Output. Standard Error is where error messages are put. Normally, they're placed on your terminal screen just like Standard Output. However, if you redirect your output into a file, error messages are still printed to the terminal window. In this case, redirecting the output to a file will also redirect any error messages too.
Those are bash built-ins. You should read the bash man page or, for getopts, try help getopts
One at a time (it's really annoying to type on ipad hence switched to laptop):
local lets you define local variables (within the scope of a function)
getopts is a bash builtin which implements getopt-style argument processing (the -a, -b... type arguments)
case is the bash form for a switch statement. The syntax is
case: case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
shift shifts all of the arguments by 1 (so that the second argument becomes the first, third becomes second, ...) similar to perl shift. If you specify an argument, it will shift by that many indices (so shift 2 will assign $3 -> $1, $4 -> $2, ...)
$# is the number of arguments passed to the function
${2:-*} is a default argument form. Basically, it looks at the second argument ($2 is the second arg) and if it is not assigned, it will replace it with *.
2>&- is output redirection (in this case, for standard error)

How to get arguments with flags in Bash

I know that I can easily get positioned parameters like this in bash:
$0 or $1
I want to be able to use flag options like this to specify for what each parameter is used:
mysql -u user -h host
What is the best way to get -u param value and -h param value by flag instead of by position?
This example uses Bash's built-in getopts command and is from the Google Shell Style Guide:
a_flag=''
b_flag=''
files=''
verbose='false'
print_usage() {
printf "Usage: ..."
}
while getopts 'abf:v' flag; do
case "${flag}" in
a) a_flag='true' ;;
b) b_flag='true' ;;
f) files="${OPTARG}" ;;
v) verbose='true' ;;
*) print_usage
exit 1 ;;
esac
done
Note: If a character is followed by a colon (e.g. f:), that option is expected to have an argument.
Example usage: ./script -v -a -b -f filename
Using getopts has several advantages over the accepted answer:
the while condition is a lot more readable and shows what the accepted options are
cleaner code; no counting the number of parameters and shifting
you can join options (e.g. -a -b -c → -abc)
However, a big disadvantage is that it doesn't support long options, only single-character options.
This is the idiom I usually use:
while test $# -gt 0; do
case "$1" in
-h|--help)
echo "$package - attempt to capture frames"
echo " "
echo "$package [options] application [arguments]"
echo " "
echo "options:"
echo "-h, --help show brief help"
echo "-a, --action=ACTION specify an action to use"
echo "-o, --output-dir=DIR specify a directory to store output in"
exit 0
;;
-a)
shift
if test $# -gt 0; then
export PROCESS=$1
else
echo "no process specified"
exit 1
fi
shift
;;
--action*)
export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'`
shift
;;
-o)
shift
if test $# -gt 0; then
export OUTPUT=$1
else
echo "no output dir specified"
exit 1
fi
shift
;;
--output-dir*)
export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'`
shift
;;
*)
break
;;
esac
done
Key points are:
$# is the number of arguments
while loop looks at all the arguments supplied, matching on their values inside a case statement
shift takes the first one away. You can shift multiple times inside of a case statement to take multiple values.
getopt is your friend.. a simple example:
function f () {
TEMP=`getopt --long -o "u:h:" "$#"`
eval set -- "$TEMP"
while true ; do
case "$1" in
-u )
user=$2
shift 2
;;
-h )
host=$2
shift 2
;;
*)
break
;;
esac
done;
echo "user = $user, host = $host"
}
f -u myself -h some_host
There should be various examples in your /usr/bin directory.
I propose a simple TLDR:; example for the un-initiated.
Create a bash script called greeter.sh
#!/bin/bash
while getopts "n:" arg; do
case $arg in
n) Name=$OPTARG;;
esac
done
echo "Hello $Name!"
You can then pass an optional parameter -n when executing the script.
Execute the script as such:
$ bash greeter.sh -n 'Bob'
Output
$ Hello Bob!
Notes
If you'd like to use multiple parameters:
extend while getops "n:" arg: do with more paramaters such as
while getops "n:o:p:" arg: do
extend the case switch with extra variable assignments. Such as o) Option=$OPTARG and p) Parameter=$OPTARG
To make the script executable:
chmod u+x greeter.sh
I think this would serve as a simpler example of what you want to achieve. There is no need to use external tools. Bash built in tools can do the job for you.
function DOSOMETHING {
while test $# -gt 0; do
case "$1" in
-first)
shift
first_argument=$1
shift
;;
-last)
shift
last_argument=$1
shift
;;
*)
echo "$1 is not a recognized flag!"
return 1;
;;
esac
done
echo "First argument : $first_argument";
echo "Last argument : $last_argument";
}
This will allow you to use flags so no matter which order you are passing the parameters you will get the proper behavior.
Example :
DOSOMETHING -last "Adios" -first "Hola"
Output :
First argument : Hola
Last argument : Adios
You can add this function to your profile or put it inside of a script.
Thanks!
Edit :
Save this as a a file and then execute it as yourfile.sh -last "Adios" -first "Hola"
#!/bin/bash
while test $# -gt 0; do
case "$1" in
-first)
shift
first_argument=$1
shift
;;
-last)
shift
last_argument=$1
shift
;;
*)
echo "$1 is not a recognized flag!"
return 1;
;;
esac
done
echo "First argument : $first_argument";
echo "Last argument : $last_argument";
Another alternative would be to use something like the below example which would allow you to use long --image or short -i tags and also allow compiled -i="example.jpg" or separate -i example.jpg methods of passing in arguments.
# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();
# declaring an index integer
declare -i index=1;
# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value)
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";
variables["--git-user"]="git_user";
variables["-gb"]="git_branch";
variables["--git-branch"]="git_branch";
variables["-dbr"]="db_fqdn";
variables["--db-redirect"]="db_fqdn";
variables["-e"]="environment";
variables["--environment"]="environment";
# $# here represents all arguments passed in
for i in "$#"
do
arguments[$index]=$i;
prev_index="$(expr $index - 1)";
# this if block does something akin to "where $i contains ="
# "%=*" here strips out everything from the = to the end of the argument leaving only the label
if [[ $i == *"="* ]]
then argument_label=${i%=*}
else argument_label=${arguments[$prev_index]}
fi
# this if block only evaluates to true if the argument label exists in the variables array
if [[ -n ${variables[$argument_label]} ]]
then
# dynamically creating variables names using declare
# "#$argument_label=" here strips out the label leaving only the value
if [[ $i == *"="* ]]
then declare ${variables[$argument_label]}=${i#$argument_label=}
else declare ${variables[$argument_label]}=${arguments[$index]}
fi
fi
index=index+1;
done;
# then you could simply use the variables like so:
echo "$git_user";
I like Robert McMahan's answer the best here as it seems the easiest to make into sharable include files for any of your scripts to use. But it seems to have a flaw with the line if [[ -n ${variables[$argument_label]} ]] throwing the message, "variables: bad array subscript". I don't have the rep to comment, and I doubt this is the proper 'fix,' but wrapping that if in if [[ -n $argument_label ]] ; then cleans it up.
Here's the code I ended up with, if you know a better way please add a comment to Robert's answer.
Include File "flags-declares.sh"
# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();
# declaring an index integer
declare -i index=1;
Include File "flags-arguments.sh"
# $# here represents all arguments passed in
for i in "$#"
do
arguments[$index]=$i;
prev_index="$(expr $index - 1)";
# this if block does something akin to "where $i contains ="
# "%=*" here strips out everything from the = to the end of the argument leaving only the label
if [[ $i == *"="* ]]
then argument_label=${i%=*}
else argument_label=${arguments[$prev_index]}
fi
if [[ -n $argument_label ]] ; then
# this if block only evaluates to true if the argument label exists in the variables array
if [[ -n ${variables[$argument_label]} ]] ; then
# dynamically creating variables names using declare
# "#$argument_label=" here strips out the label leaving only the value
if [[ $i == *"="* ]]
then declare ${variables[$argument_label]}=${i#$argument_label=}
else declare ${variables[$argument_label]}=${arguments[$index]}
fi
fi
fi
index=index+1;
done;
Your "script.sh"
. bin/includes/flags-declares.sh
# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value)
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";
variables["--git-user"]="git_user";
variables["-gb"]="git_branch";
variables["--git-branch"]="git_branch";
variables["-dbr"]="db_fqdn";
variables["--db-redirect"]="db_fqdn";
variables["-e"]="environment";
variables["--environment"]="environment";
. bin/includes/flags-arguments.sh
# then you could simply use the variables like so:
echo "$git_user";
echo "$git_branch";
echo "$db_fqdn";
echo "$environment";
#!/bin/bash
if getopts "n:" arg; then
echo "Welcome $OPTARG"
fi
Save it as sample.sh
and try running
sh sample.sh -n John
in your terminal.
If you're familiar with Python argparse, and don't mind calling python to parse bash arguments, there is a piece of code I found really helpful and super easy to use called argparse-bash
https://github.com/nhoffman/argparse-bash
Example take from their example.sh script:
#!/bin/bash
source $(dirname $0)/argparse.bash || exit 1
argparse "$#" <<EOF || exit 1
parser.add_argument('infile')
parser.add_argument('outfile')
parser.add_argument('-a', '--the-answer', default=42, type=int,
help='Pick a number [default %(default)s]')
parser.add_argument('-d', '--do-the-thing', action='store_true',
default=False, help='store a boolean [default %(default)s]')
parser.add_argument('-m', '--multiple', nargs='+',
help='multiple values allowed')
EOF
echo required infile: "$INFILE"
echo required outfile: "$OUTFILE"
echo the answer: "$THE_ANSWER"
echo -n do the thing?
if [[ $DO_THE_THING ]]; then
echo " yes, do it"
else
echo " no, do not do it"
fi
echo -n "arg with multiple values: "
for a in "${MULTIPLE[#]}"; do
echo -n "[$a] "
done
echo
I had trouble using getopts with multiple flags, so I wrote this code. It uses a modal variable to detect flags, and to use those flags to assign arguments to variables.
Note that, if a flag shouldn't have an argument, something other than setting CURRENTFLAG can be done.
for MYFIELD in "$#"; do
CHECKFIRST=`echo $MYFIELD | cut -c1`
if [ "$CHECKFIRST" == "-" ]; then
mode="flag"
else
mode="arg"
fi
if [ "$mode" == "flag" ]; then
case $MYFIELD in
-a)
CURRENTFLAG="VARIABLE_A"
;;
-b)
CURRENTFLAG="VARIABLE_B"
;;
-c)
CURRENTFLAG="VARIABLE_C"
;;
esac
elif [ "$mode" == "arg" ]; then
case $CURRENTFLAG in
VARIABLE_A)
VARIABLE_A="$MYFIELD"
;;
VARIABLE_B)
VARIABLE_B="$MYFIELD"
;;
VARIABLE_C)
VARIABLE_C="$MYFIELD"
;;
esac
fi
done
So here it is my solution. I wanted to be able to handle boolean flags without hyphen, with one hyphen, and with two hyphen as well as parameter/value assignment with one and two hyphens.
# Handle multiple types of arguments and prints some variables
#
# Boolean flags
# 1) No hyphen
# create Assigns `true` to the variable `CREATE`.
# Default is `CREATE_DEFAULT`.
# delete Assigns true to the variable `DELETE`.
# Default is `DELETE_DEFAULT`.
# 2) One hyphen
# a Assigns `true` to a. Default is `false`.
# b Assigns `true` to b. Default is `false`.
# 3) Two hyphens
# cats Assigns `true` to `cats`. By default is not set.
# dogs Assigns `true` to `cats`. By default is not set.
#
# Parameter - Value
# 1) One hyphen
# c Assign any value you want
# d Assign any value you want
#
# 2) Two hyphens
# ... Anything really, whatever two-hyphen argument is given that is not
# defined as flag, will be defined with the next argument after it.
#
# Example:
# ./parser_example.sh delete -a -c VA_1 --cats --dir /path/to/dir
parser() {
# Define arguments with one hyphen that are boolean flags
HYPHEN_FLAGS="a b"
# Define arguments with two hyphens that are boolean flags
DHYPHEN_FLAGS="cats dogs"
# Iterate over all the arguments
while [ $# -gt 0 ]; do
# Handle the arguments with no hyphen
if [[ $1 != "-"* ]]; then
echo "Argument with no hyphen!"
echo $1
# Assign true to argument $1
declare $1=true
# Shift arguments by one to the left
shift
# Handle the arguments with one hyphen
elif [[ $1 == "-"[A-Za-z0-9]* ]]; then
# Handle the flags
if [[ $HYPHEN_FLAGS == *"${1/-/}"* ]]; then
echo "Argument with one hyphen flag!"
echo $1
# Remove the hyphen from $1
local param="${1/-/}"
# Assign true to $param
declare $param=true
# Shift by one
shift
# Handle the parameter-value cases
else
echo "Argument with one hyphen value!"
echo $1 $2
# Remove the hyphen from $1
local param="${1/-/}"
# Assign argument $2 to $param
declare $param="$2"
# Shift by two
shift 2
fi
# Handle the arguments with two hyphens
elif [[ $1 == "--"[A-Za-z0-9]* ]]; then
# NOTE: For double hyphen I am using `declare -g $param`.
# This is the case because I am assuming that's going to be
# the final name of the variable
echo "Argument with two hypens!"
# Handle the flags
if [[ $DHYPHEN_FLAGS == *"${1/--/}"* ]]; then
echo $1 true
# Remove the hyphens from $1
local param="${1/--/}"
# Assign argument $2 to $param
declare -g $param=true
# Shift by two
shift
# Handle the parameter-value cases
else
echo $1 $2
# Remove the hyphens from $1
local param="${1/--/}"
# Assign argument $2 to $param
declare -g $param="$2"
# Shift by two
shift 2
fi
fi
done
# Default value for arguments with no hypheb
CREATE=${create:-'CREATE_DEFAULT'}
DELETE=${delete:-'DELETE_DEFAULT'}
# Default value for arguments with one hypen flag
VAR1=${a:-false}
VAR2=${b:-false}
# Default value for arguments with value
# NOTE1: This is just for illustration in one line. We can well create
# another function to handle this. Here I am handling the cases where
# we have a full named argument and a contraction of it.
# For example `--arg1` can be also set with `-c`.
# NOTE2: What we are doing here is to check if $arg is defined. If not,
# check if $c was defined. If not, assign the default value "VD_"
VAR3=$(if [[ $arg1 ]]; then echo $arg1; else echo ${c:-"VD_1"}; fi)
VAR4=$(if [[ $arg2 ]]; then echo $arg2; else echo ${d:-"VD_2"}; fi)
}
# Pass all the arguments given to the script to the parser function
parser "$#"
echo $CREATE $DELETE $VAR1 $VAR2 $VAR3 $VAR4 $cats $dir
Some references
The main procedure was found here.
More about passing all the arguments to a function here.
More info regarding default values here.
More info about declare do $ bash -c "help declare".
More info about shift do $ bash -c "help shift".

How do I access arguments to functions if there are more than 9 arguments?

With first 9 arguments being referred from $1-$9, $10 gets interpreted as $1 followed by a 0. How do I account for this and access arguments to functions greater than 10?
Thanks.
Use :
#!/bin/bash
echo ${10}
To test the difference with $10, code in foo.sh :
#!/bin/bash
echo $10
echo ${10}
Then :
$ ./foo.sh first 2 3 4 5 6 7 8 9 10
first0
10
the same thing is true if you have :
foobar=42
foo=FOO
echo $foobar # echoes 42
echo ${foo}bar # echoes FOObar
Use {} when you want to remove ambiguities ...
my2c
If you are using bash, then you can use ${10}.
${...} syntax seems to be POSIX-compliant in this particular case, but it might be preferable to use the command shift like that :
while [ "$*" != "" ]; do
echo "Arg: $1"
shift
done
EDIT: I noticed I didn't explain what shift does. It just shift the arguments of the script (or function). Example:
> cat script.sh
echo "$1"
shift
echo "$1"
> ./script.sh "first arg" "second arg"
first arg
second arg
In case it can help, here is an example with getopt/shift :
while getopts a:bc OPT; do
case "$OPT" in
'a')
ADD=1
ADD_OPT="$OPTARG"
;;
'b')
BULK=1
;;
'c')
CHECK=1
;;
esac
done
shift $( expr $OPTIND - 1 )
FILE="$1"
In general, to be safe that the whole of a given string is used for the variable name when Bash is interpreting the code, you need to enclose it in braces: ${10}

Resources