2014-12-03 4 views
1

Мне нужно посчитать процентное изменение между двумя значениями.BASH: Процентное изменение - как его рассчитать? Как получить абсолютное значение без bc?

Код я здесь:

echo $time1 
echo $time2 
pc=$(((($time2 - $time1)/$time1 * 100))) 
echo $pc 

приносит такой вывод в консоль (с set -xe опцией)

+ echo 1800 
1800 
+ echo 1000 
1000 
+ pc=0 
+ echo 0 

Код внутри математическое выражение, кажется, написано правильно, по-прежнему, я получите -80 или около того. Почему это происходит со мной?

Вторая часть вопроса. У меня нет доступа, и у меня не будет доступа к команде bc. Из того, что я слышал, это может дать мне абсолютное значение числа, которое у меня есть.

Итак, без команды bc - это будет хорошей идеей для условия IF?

if (((("$pc" > 20 || (("$pc" < -20)); then... 
+0

Bash делает только целочисленную арифметику, поэтому, если '$ time2 - $ time1' меньше, чем' $ time1', тогда деление всегда будет равным нулю. Однако, если вы слегка измените порядок выражения, как умножение перед делением, результат должен быть немного лучше. –

+1

Это требование, чтобы это было сделано в чистом bash? –

+0

@TomFenech, нет, это можно сделать в любом инструменте, доступном для меня. Например, можно сделать в perl. – dziki

ответ

3

Как вы уже отметили, что это не нужно делать это в Баш, я бы рекомендовал использовать AWK:

awk -v t1="$time1" -v t2="$time2" 'BEGIN{print (t2-t1)/t1 * 100}' 

Обычно, AWK предназначен для обработки файлов, но вы можете использовать BEGIN блок выполнять вычисления, не передавая ему никаких файлов. Переменные Shell могут быть переданы ему с помощью переключателя -v.

Если вы хотите, чтобы результат округляется, вы всегда можете использовать printf:

awk -v t1="$time1" -v t2="$time2" 'BEGIN{printf "%.0f", (t2-t1)/t1 * 100}' 

%.0f спецификатор формата приводит к тому, результат округляется до целого числа (с плавающей запятой с 0 знаков после запятой).

+0

В зависимости от того, как значения получены в первую очередь и что должен делать условный код, возможно, что вы сможете выполнить все это в awk. –

+0

Это приятное решение, и Im, его повышающий, nah, Im, обозначающий его как решение, но мне нужно защитить себя от некоторых случаев, поэтому в настоящее время я работаю над скриптом perl. Но все же, спасибо за ответ! – dziki

+0

Нет проблем. Для быстрых вычислений с плавающей запятой, включающих переменные оболочки, awk может быть полезен, но это немного злоупотребляет блоком 'BEGIN', поэтому для более сложных вещей Perl может быть лучшим вариантом. С другой стороны, если две переменные действительно считываются из файла, использование awk может быть лучшим решением. –

1

При правильном округлением nicer пробелов, и без лишних $ признаков:

pc=$((((((time2 - time1) * 1000)/time1) + (time2 > time1 ? 5 : -5))/10)) 
1

Может быть, вы хотите предпочесть бв + AWK смешанной линии, что-то вроде этого:

total=70 
item=30 
percent=$(echo %$(echo "scale = 2; ($item/$total)" | bc -l | awk -F '.' '{print $2}')) 
echo $percent 
+0

полезно, если 100 * (time1-time2) может превышать max int. –

1

Некоторые примечания:

  • Математика основана на целых числах, поэтому вы получаете нулевое раннее, потому что вы делите
  • Синтаксис $(()) расширит переменные, так что используйте time1 вместо $time1
  • Процент ответ -44 не -80

Вот некоторые примеры:

echo $((time2-time1)) # Output: -800 
echo $(((time2-time1)/time1)) # Output: 0. see it's already zero! 
echo $(((time2-time1)/time1*100)) # Output: 0. it's still zero and still 'incorrect' 
echo $(((time2-time1)*100)) # Output: -80000. fix by multiplying before dividing 
echo $(((time2-time1)*100/time1)) # Output: -44. this is the 'correct' answer 
echo $(((time2-time1)*100/time2)) # Output: -80. note this is also an 'incorrect' answer 
Смежные вопросы