How to make the argument схвати 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 в optional arguments.

When I call the function with 2 arguments I get ошибка:

SUM 3 8
bash: 3+8+++++++: syntax error: operand expected (error token is "+")

Заметьте BOLD: first argument and second argument пашите я вынудил 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 не result.

13
задан 6 March 2015 в 13:03

7 ответов

Если Вы не передадите споры с пробелами:

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

Эффект:

$ sum 1 2 3
6

Объяснение:

  1. <<<"some string" подача в только "some string" как вход. Думайте о нем как о сокращении от echo "some string" |. Это называют Здесь Строка.
  2. "$@" расширяется во все позиционные параметры, разделенные пробелами. Это эквивалентно "$1 $2 ...".
  3. Следовательно, tr ' ' '+' <<<"$@" выводы "$1+$2+$3...", который оценен внешним $(( )).
  4. [[ -n $2 ]] тесты, если второй параметр непуст. Вы могли заменить [[ -n $2 ]] && с [[ -z $2 ]] ||.

Иначе:

sum() {
[[ -n $2 ]] && (IFS=+; echo $(( $* )))
}

Объяснение:

  1. $* точно так же, как $@, за исключением того, что параметры не разделяются пробелами, но первым символом Внутреннего Разделителя полей (IFS). С IFS=+, это расширяется до "1$ + 2$ +...". Посмотрите то, Что различие между $* и $?
  2. Мы устанавливаем IFS в подоболочке (отмечают окружающие круглые скобки) так, чтобы основная оболочка не была затронута. IFS по умолчанию: \t\n (пространство, вкладка, новая строка). Это - альтернатива использованию local переменные.

Теперь отвечать на Ваш вопрос:

Можно использовать значение по умолчанию для любой переменной или параметра. Также:

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

Или:

SUM() { 
 echo "The sum is $(($1+$2+${3:=0}+${4:=0}+${5:=0}+${6:=0}+${7:=0}+${8:=0}+${9:=0}))" || false
}
22
ответ дан 23 November 2019 в 03:10

Вы могли использовать рекурсивное определение, которое завершается, когда sum вызывается без аргументов. Мы используем то, которое test без аргументов оценивает к false.

sum () {
    test $1 && echo $(( $1 + $(shift; sum $@) )) || echo 0
}
4
ответ дан 23 November 2019 в 03:10

Взгляните на shift оператор. Это сместит аргументы 2 и вперед к позициям 1 и вперед, отбрасывая аргумент 1.

sum () {
    local total=0;
    while [ $# -gt 0 ]; do
        total=$(($total + $1))
        shift
    done
    echo $total
}
17
ответ дан 23 November 2019 в 03:10

Используйте 0 в качестве значений по умолчанию за 1$ к 9$:

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

От 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.

Примеры:

$ SUM

сумма 0

$ SUM 1 2 

, сумма равняется 3

$ SUM 1 1 1 1 1 1 1 1 1 

, сумма равняется 9

<час> Тот же вывод с awk:
SUM() {
  echo -e ${@/%/\\n} | awk '{s+=$1} END {print "The sum is " s}'
}
2
ответ дан 23 November 2019 в 03:10

Попробуйте это:

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

Это произведет 12 и 30.

$@ относится к параметру, $# возвраты количество параметра, в этом случае 3 или 11.

Протестированный на linux redhat 4

3
ответ дан 23 November 2019 в 03:10

Это - также мое собственное решение, я попробовал его и нашел:

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

$ SUM 4 6 5
The sum is 15

, Но ответ @muru хорош.

1
ответ дан 23 November 2019 в 03:10

Вы могли просто использовать немного цикла:

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

Лично, хотя, я просто использовал бы perl или awk вместо этого:

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

или

sum(){
 echo "$@" | awk '{for(i=1; i<=NF; i++){k+=$i} print k}'
}
2
ответ дан 23 November 2019 в 03:10

Другие вопросы по тегам:

Похожие вопросы: