Let's face it, using positional arguments like $1
and $2
for your arguments is not very descriptive and not very flexible. There is a better way to supply arguments: with this simple trick you'll get --named arguments --in your-script
, which is waaaay better 🤓.
Parsing script arguments
The following script parses all arguments and turns them into variables:
while [ $# -gt 0 ]; do
if [[ $1 == "--"* ]]; then
v="${1/--/}"
declare "$v"="$2"
shift
fi
shift
done
echo "\$this: '$this' \$a: '$a'"
When we execute the script with: ./test.sh --this is --a test
, it returns:
$this: 'is' $a: 'test'
Note: this method is not very strict, it might skip parameters that are not adhering to the double dash format. If you want to support --single-parameters, check Support for --help?
Note 2: this method does not work with set -u
🤷
Argument validation
First, let's define a usage
function to show how our script works:
programname=$0
function usage {
echo ""
echo "Deploys an ECR image to Atlas using GitOps and ArgoCD."
echo ""
echo "usage: $programname --service_name string --tag string --atlas string --env string "
echo ""
echo " --service_name string name of the service"
echo " (example: blaze-search-term-redirect-service)"
echo " --tag string tag of the image to deploy"
echo " (example: 804-a325d6a)"
echo " --namespace string namespace of the cluster"
echo " (example: eos)"
echo " --env string env to which to deploy the tag"
echo " (example: dev)"
echo ""
}
Next, let's define a die
function:
function die {
printf "Script failed: %s\n\n" "$1"
exit 1
}
Now, let's check if the parameters are supplied. If one of the parameters is missing, display usage and terminate the script. We use the -z conditional expression to check if the variable is empty:
if [[ -z $service_name ]]; then
usage
die "Missing parameter --service_name"
elif [[ -z $tag ]]; then
usage
die "Missing parameter --tag"
elif [[ -z $namespace ]]; then
usage
die "Missing parameter --namespace"
elif [[ -z $env ]]; then
usage
die "Missing parameter --env"
fi
Support for --help?
The easiest way of adding --help
to your script, is by adding it to the loop that turns the arguments into variables:
while [ $# -gt 0 ]; do
if [[ $1 == "--help" ]]; then
usage
exit 0
elif [[ $1 == "--"* ]]; then
v="${1/--/}"
declare "$v"="$2"
shift
fi
shift
done
Any singular parameter can be added to this loop.
How about defaults?
Here you have 2 strategies:
- Declare the variables at the top of your script and initialize them with defaults.
- Use parameter expansion:
my_parameter=${my_parameter:-default value}
Parameter expansion
If you use parameter expansion, you need to know that the empty string ""
will also be replaced. Observe the following script:
my_parameter="${my_parameter:-default value}"
printf "%s\n\n" "$my_parameter"
It will give the following output:
$ ./test.sh
default value
$ ./test.sh --my_parameter "my value"
my value
$ ./test.sh --my_parameter ""
default value
So, settings the defaults at the top of the script has my preference.
Write better scripts: use ShellCheck
The article Please stop writing shell scripts makes some excellent points on why writing a bash script is hard for programmers: bash behavior is most likely not like the programming language you're familiar with. The ShellCheck extension for Visual Studio Code will help you catch some of the pitfalls. With every "offence", it links to a wiki article for education:
Show the explanation of SC2086.
Conclusion
Adding named arguments to a bash script is pretty easy. There are some caveats, as you might "override" arguments in your script from the outside. If you declare the arguments at the beginning of your script and the reset of the parameters after the while
section, you mitigate that risk.
Changelog
2022-04-04: made the parameter validation script a bit shorter by using elif
.
Top comments (0)