How to make the argument as optional in bash?
In below function with 9 arguments:
SUM() {
echo "The sum is $(($1+$2+$3+$4+$5+$6+$7+$8+$9))"
}
I want to make the second arguments to the next(3..9) become a optional arguments.
When I call the function with 2 arguments I get error:
SUM 3 8
bash: 3+8+++++++: syntax error: operand expected (error token is "+")
Note BOLD: first argument and second argument are force arguments and not optional for function. I only want second arguments to the next is optional and when I call the function less than 2 args the function must return no result.
Solution 1:
If you won't pass arguments with spaces:
sum() {
[[ -n $2 ]] && echo $(( $(tr ' ' '+' <<<"$@") ))
}
Effect:
$ sum 1 2 3
6
Explanation:
-
<<<"some string"
feeds in only"some string"
as the input. Think of it as shorthand forecho "some string" |
. It is called a Here String. -
"$@"
expands into all the positional parameters, separated by spaces. It is equivalent to"$1 $2 ..."
. - Hence,
tr ' ' '+' <<<"$@"
outputs"$1+$2+$3..."
, which is evaluated by the outer$(( ))
. -
[[ -n $2 ]]
tests if the second parameter is non-empty. You could replace[[ -n $2 ]] &&
with[[ -z $2 ]] ||
.
Another way:
sum() {
[[ -n $2 ]] && (IFS=+; echo $(( $* )))
}
Explanation:
-
$*
is just like$@
, except that the parameters are not separated by spaces, but by the first character of the Internal Field Separator (IFS
). WithIFS=+
, it expands to "$1+$2+...". See What is the difference between $* and $@? - We set
IFS
in a subshell (note the surrounding parentheses) so that the main shell isn't affected.IFS
is, by default:\t\n
(space, tab, newline). This is an alternative to usinglocal
variables.
Now to answer your question:
You can use a default value for any variable or parameter. Either:
SUM() {
echo "The sum is $(($1+$2+${3:-0}+${4:-0}+${5:-0}+${6:-0}+${7:-0}+${8:-0}+${9:-0}))" || false
}
Or:
SUM() {
echo "The sum is $(($1+$2+${3:=0}+${4:=0}+${5:=0}+${6:=0}+${7:=0}+${8:=0}+${9:=0}))" || false
}
Solution 2:
Have a look at the shift
operator. It will shift arguments 2 and onward to positions 1 and onward, discarding argument 1.
sum () {
local total=0;
while [ $# -gt 0 ]; do
total=$(($total + $1))
shift
done
echo $total
}