Як зробити аргумент як необов’язковий в bash?


13

Нижче функція з 9 аргументами:

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

Я хочу, щоб другі аргументи до наступного (3..9) стали необов'язковими аргументами .

Коли я викликаю функцію з 2 аргументами, я отримую помилку:

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

Примітка BOLD : перший аргумент і другий аргумент - це аргументи сили, а не є обов'язковими для функції. Я хочу лише, щоб другий аргумент до наступного був необов’язковим, і коли я викликаю функцію менше ніж 2 аргументи, функція не повинна повертати жодного результату.

Відповіді:


22

Якщо ви не передасте аргументи з пробілами:

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

Ефект:

$ sum 1 2 3
6

Пояснення:

  1. <<<"some string"подається лише "some string"як вхідний. Подумайте про це як скорочення echo "some string" |. Він називається Here 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
}

6
Вишуканий! Я знаю, що коментарі не призначені для безоплатних компліментів і подяк, але це рішення просто ... зле! :-)
zwets

17

Погляньте на shiftоператора. Він змістить аргументи 2 і вперед на позиції 1 і вперед, відкинувши аргумент 1.

sum () {
    local total=0;
    while [ $# -gt 0 ]; do
        total=$(($total + $1))
        shift
    done
    echo $total
}

4

Ви можете використовувати рекурсивне визначення, яке закінчується, коли sumвикликається без аргументів. Ми використовуємо той факт, який testбез аргументів не оцінює false.

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

3

Спробуйте це:

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


2

Ви можете просто використати невеликий цикл:

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

Використовуйте 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}'
}

1

Я також спробував це і знайшов:

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

$ SUM 4 6 5
The sum is 15

Але відповідь @ muru хороша.


+1: Цікаве використання двох арифметичних розширень для оцінки порожніх параметрів до нуля.
муру

1
@muru спасибі, але в цьому випадку у моїй відповіді ми не використовуємо більше 9 аргументів, і ми маємо використовувати групу аргументів, щоб передати більше 9. дякую за вашу ідеальну відповідь.
αғsnιη
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.