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.
Если Вы не передадите споры с пробелами:
sum() {
[[ -n $2 ]] && echo $(( $(tr ' ' '+' <<<"$@") ))
}
Эффект:
$ sum 1 2 3
6
Объяснение:
<<<"some string"
подача в только "some string"
как вход. Думайте о нем как о сокращении от echo "some string" |
. Это называют Здесь Строка."$@"
расширяется во все позиционные параметры, разделенные пробелами. Это эквивалентно "$1 $2 ..."
.tr ' ' '+' <<<"$@"
выводы "$1+$2+$3..."
, который оценен внешним $(( ))
.[[ -n $2 ]]
тесты, если второй параметр непуст. Вы могли заменить [[ -n $2 ]] &&
с [[ -z $2 ]] ||
.Иначе:
sum() {
[[ -n $2 ]] && (IFS=+; echo $(( $* )))
}
Объяснение:
$*
точно так же, как $@
, за исключением того, что параметры не разделяются пробелами, но первым символом Внутреннего Разделителя полей (IFS
). С IFS=+
, это расширяется до "1$ + 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
}
Вы могли использовать рекурсивное определение, которое завершается, когда sum
вызывается без аргументов. Мы используем то, которое test
без аргументов оценивает к false
.
sum () {
test $1 && echo $(( $1 + $(shift; sum $@) )) || echo 0
}
Взгляните на shift
оператор. Это сместит аргументы 2 и вперед к позициям 1 и вперед, отбрасывая аргумент 1.
sum () {
local total=0;
while [ $# -gt 0 ]; do
total=$(($total + $1))
shift
done
echo $total
}
Используйте 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}'
}
Попробуйте это:
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
Это - также мое собственное решение, я попробовал его и нашел:
SUM() {
echo "The sum is $(($1+$2+$[$3]+$[$4]+$[$5]+$[$6]+$[$7]+$[$8]+$[$9]))"
}
$ SUM 4 6 5
The sum is 15
, Но ответ @muru хорош.
Вы могли просто использовать немного цикла:
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}'
}