I want to know what principles I should use in order to write a bash script that takes its parameters in any given order. For example:
What I am asking here is:
Is there a specific way (or even programming technique) I can use so that the parameters can be passed in any given order (besides the fact that the filename should always follow the -f parameter?
Here are some invoking examples:
The above two executions should produce the very same example!
When answering please do keep in mind that the real problem has many more parameters and different outcomes!
Here's the script I wrote to achieve this:
#!/bin/bash
# The code below was written to replace the -print and -delete options for
# -p and -d respectively, because getopts can't handle long args, I suggest
# you only use arguments of single letters to make your code more simple, but if
# you can't avoid it then this is a workaround
for ARGS in "$@"; do
shift
case "$ARGS" in
"-print") set -- "$@" "-p" ;;
"-delete") set -- "$@" "-d" ;;
*) set -- "$@" "$ARGS"
esac
done
# getopts works like this: you put all your arguments between single quotes
# if you put a ':' character after the argument letter (just like I did with
# the 'f' letter in the example below), it means this argument NEEDS an extra
# parameter. If you just use letters without the ':' it means it doesn't need
# anything but the argument itself (it's what I did for the '-p' and '-d' options)
while getopts 'f:pd' flag; do
case "${flag}" in
f) FILE=${OPTARG} ;;
p) COMMAND="print" ;;
d) COMMAND="delete" ;;
esac
done
echo "$COMMAND $FILE"
And below examples of it running:
$ ./script.sh -f filename -print
print filename
$ ./script.sh -print -f filename
print filename
$ ./script.sh -f filename -delete
delete filename
$ ./script.sh -delete -f filename
delete filename
The previous solution is a good starting point, I played around with it for being able to accept multiple arguments to a flag, and I think this is a bit better style (less unused variables too):
#!/bin/bash
while [ $# -gt 0 ]; do
case "$1" in
--file|-f) filename=$2 ; shift;;
--print|-p) printCommand ;;
--delete|-d) deleteCommand ;;
*) break
esac
shift
done
Also note shift can take number of moves as an argument, this helps to keep it tidy. eg:
--two-files) filename1=$2; filename2=$3; shift 2;;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With