13

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.

0

7 Answers 7

22

If you won't pass arguments with spaces:

sum() {  
[[ -n $2 ]] && echo $(( $(tr ' ' '+' <<<"$@") ))
}

Effect:

$ sum 1 2 3
6

Explanation:

  1. <<<"some string" feeds in only "some string" as the input. Think of it as shorthand for echo "some string" |. It is called a Here String.
  2. "$@" expands into all the positional parameters, separated by spaces. It is equivalent to "$1 $2 ...".
  3. Hence, tr ' ' '+' <<<"$@" outputs "$1+$2+$3...", which is evaluated by the outer $(( )).
  4. [[ -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:

  1. $* is just like $@, except that the parameters are not separated by spaces, but by the first character of the Internal Field Separator (IFS). With IFS=+, it expands to "$1+$2+...". See What is the difference between $* and $@?
  2. 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 using local 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
}
1
  • 6
    Nifty! I know comments aren't meant for gratuitous compliments and thanks, but this solution is just ... wicked! :-)
    – zwets
    Sep 10, 2014 at 8:59
17

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
}
0
4

You could use a recursive definition which terminates when sum is invoked without arguments. We make use of the fact that test without arguments evaluates to false.

sum () {
    test $1 && echo $(( $1 + $(shift; sum $@) )) || echo 0
}
3

Try this:

SUM () {
 [ $# -lt "2" ] && return 1
 for par in $@; do
   local sum=`expr $sum + $par`
 done
 echo $sum
 return 0
}

SUM 3 4 5
SUM 3 4 5 1 1 1 1 2 3 4 5

This will output 12 and 30.

$@ refers to parameter, $# returns the number of parameter, in this case 3 or 11.

Tested on linux redhat 4

0
2

You could just use a little loop:

sum(){
    t=0;
    for i in "$@"; do t=$((t + i )); done
    echo $t;
}

Personally though, I'd just use perl or awk instead:

sum(){
 echo "$@" | perl -lane '$s+=$_ for @F; print $s'
}

or

sum(){
 echo "$@" | awk '{for(i=1; i<=NF; i++){k+=$i} print k}'
}
2

Use 0 as default values for $1 to $9:

SUM() { 
    echo "The sum is $((${1:-0}+${2:-0}+${3:-0}+${4:-0}+${5:-0}+${6:-0}+${7:-0}+${8:-0}+${9:-0}))"
}

From man bash:

${parameter:-word}
    Use Default Values. If parameter is unset or null, the expansion
    of word is substituted. Otherwise, the value of parameter is
    substituted.

Examples:

$ SUM

The sum is 0

$ SUM 1 2 

The sum is 3

$ SUM 1 1 1 1 1 1 1 1 1 

The sum is 9


Same output with awk:

SUM() {
  echo -e ${@/%/\\n} | awk '{s+=$1} END {print "The sum is " s}'
}
1

It's also my own solution I tried it and found:

SUM() { 
    echo "The sum is $(($1+$2+$[$3]+$[$4]+$[$5]+$[$6]+$[$7]+$[$8]+$[$9]))"
 }

$ SUM 4 6 5
The sum is 15

But @muru's answer is good.

2
  • +1: Interesting usage of two arithmetic expansions to evaluate empty parameters to zero.
    – muru
    Sep 10, 2014 at 9:29
  • 1
    @muru thanks, but in this case my answer we don't use more than 9 arguments and we have to use group of arguments to pass more than 9. thank you for your answer that's perfect. Sep 10, 2014 at 9:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .