Как я могу добавить числа в скрипте bash - PullRequest
485 голосов
/ 14 июня 2011

У меня есть этот bash-скрипт, и у меня возникла проблема в строке 16. Как я могу взять предыдущий результат строки 15 и добавить его в переменную в строке 16?

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do      
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        num= $num + $metab   (line16)
    done
    echo "$num"
 done

Ответы [ 10 ]

851 голосов
/ 14 июня 2011

Для целых чисел :

  • Использование арифметического расширения : $((EXPR))

    num=$((num1 + num2))
    num=$(($num1 + $num2))       # also works
    num=$((num1 + 2 + 3))        # ...
    num=$[num1+num2]             # old, deprecated arithmetic expression syntax
    
  • Использование внешней утилиты expr.Обратите внимание, что это необходимо только для действительно старых систем.

    num=`expr $num1 + $num2`     # whitespace for expr is important
    

Для чисел с плавающей запятой :

Bash не напрямуюподдержите это, но есть пара внешних инструментов, которые вы можете использовать:

num=$(awk "BEGIN {print $num1+$num2; exit}")
num=$(python -c "print $num1+$num2")
num=$(perl -e "print $num1+$num2")
num=$(echo $num1 + $num2 | bc)   # whitespace for echo is important

Вы также можете использовать научную нотацию (например: 2.5e+2)


Типичные ошибки:

  • При установке переменной не должно быть пробелов по обе стороны от =, иначе это заставит оболочку интерпретировать первое слово как имя приложениязапустить (например: num= или num)

    num= 1 num =2

  • bc и expr ожидают каждого числа и оператора в качестве отдельного аргумента, поэтому пробелы важны.Они не могут обрабатывать аргументы типа 3+ +4.

    num=`expr $num1+ $num2`

87 голосов
/ 14 июня 2011

Используйте арифметическое расширение $(( )).

num=$(( $num + $metab ))

См. http://tldp.org/LDP/abs/html/arithexp.html для получения дополнительной информации.

26 голосов
/ 15 июня 2011

Есть тысяча и один способ сделать это. Вот один из них, использующий dc:

dc <<<"$num1 $num2 + p"

Но если это слишком для вас (или имеет значение для переносимости), вы можете сказать

echo $num1 $num2 + p | dc

Но, возможно, вы один из тех, кто считает RPN непристойным и странным; не волнуйся! bc здесь для вас:

bc <<< "$num1 + $num2"
echo $num1 + $num2 | bc

Тем не менее, есть некоторые несвязанные улучшения, которые вы могли бы внести в свой скрипт

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do
    for j in output-$i-* ; do # for can glob directly, no need to ls
            echo "$j"

             # grep can read files, no need to use cat
            metab=$(grep EndBuffer "$j" | awk '{sum+=$2} END { print sum/120}')
            num=$(( $num + $metab ))
    done
    echo "$num"
done

EDIT:

Как описано в BASH FAQ 022 , bash изначально не поддерживает числа с плавающей запятой. Если вам необходимо суммировать числа с плавающей запятой, необходимо использовать внешний инструмент (например, bc или dc).

В этом случае решение будет

num=$(dc <<<"$num $metab + p")

Чтобы добавить накопленные числа с плавающей точкой в ​​num.

21 голосов
/ 15 июня 2011

В bash,

 num=5
 x=6
 (( num += x ))
 echo $num   # ==> 11

Обратите внимание, что bash может обрабатывать только целочисленную арифметику, поэтому, если ваша команда awk возвращает дробь, вы захотите изменить дизайн: ваш код переписан, чтобы сделать всематематика в awk.

num=0
for ((i=1; i<=2; i++)); do      
    for j in output-$i-*; do
        echo "$j"
        num=$(
           awk -v n="$num" '
               /EndBuffer/ {sum += $2}
               END {print n + (sum/120)}
           ' "$j"
        )
    done
    echo "$num"
done
16 голосов
/ 29 октября 2013

Я всегда забываю синтаксис, поэтому захожу в Google, но потом я никогда не найду тот, с которым мне знакомо: P.Это самое чистое для меня и более верное тому, что я ожидал бы на других языках.

i=0
((i++))

echo $i;
15 голосов
/ 25 октября 2013

Мне очень нравится этот метод, меньше беспорядка:

count=$[count+1]
10 голосов
/ 30 сентября 2016
 #!/bin/bash
read X
read Y
echo "$(($X+$Y))"
8 голосов
/ 30 апреля 2017

Вы должны объявить meta как целое число, а затем использовать арифметическую оценку

declare -i metab num
...
num+=metab
...

Для получения дополнительной информации см. https://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html#Shell-Arithmetic

6 голосов
/ 14 января 2017

Другой переносимый POSIX совместимый способ сделать в bash, который можно определить как функцию в .bashrc для всех арифметических операторов удобства.

addNumbers () {
    local IFS='+'
    printf "%s\n" "$(( $* ))"
}

и просто вызвать его вкомандной строки как,

addNumbers 1 2 3 4 5 100
115

Идея состоит в том, чтобы использовать Разделитель входных полей (IFS) , специальную переменную в bash, используемую для разделения слов после раскрытия и дляразбить строки на слова.Функция изменяет значение локально, чтобы использовать символ разделения слов в качестве оператора суммирования +.

Помните, что IFS изменяется локально и НЕ вступает в силу по умолчанию IFS поведение вне области действия функции.Выдержка из страницы man bash,

Оболочка обрабатывает каждый символ IFS как разделитель и разбивает результаты других расширений на слова в этих символах.Если IFS не установлен или его значение в точности равно значению по умолчанию, то последовательности, и в начале и в конце результатов предыдущих расширений игнорируются, и любая последовательность символов IFS, отсутствующая в начале или конце, служит для разделенияслова.

"$(( $* ))" представляет список аргументов, переданных для разделения на +, и позже значение суммы выводится с использованием функции printf.Функцию можно расширить, добавив область видимости и для других арифметических операций.

2 голосов
/ 20 марта 2018
#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do      
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        let num=num+metab (line 16)
    done
    echo "$num"
done
...