Shell 숫자 계산법
발췌 : http://blog.helperchoi.com/97 (좋은 글 감사합니다)
Linux 에서 Shell Script를 개발 및 사용 하다보면 연산처리가 필요 할 경우가 있으며, Linux 기반에서 사용할 수 있는 연산 처리자들은 expr, let, bc, awk 내장 연산자 등이 있다.
1. expr 사용 예시
– 아래와 같이 expr은 정수를 기준으로 사칙연산을 지원하지만 아쉽게도 부동 소수점 연산을 지원하지 않는다.
[root@s-node01 ~]#
[root@s-node01 ~]# expr 1 + 1
2
[root@s-node01 ~]# expr 1 \* 4
4
[root@s-node01 ~]# expr 1 \* -4
-4
[root@s-node01 ~]# expr -2 \* -2
4
[root@s-node01 ~]#
[root@s-node01 ~]# expr 1 + 1.5
expr: non-numeric argument
[root@s-node01 ~]#
[root@s-node01 ~]#
2. let 사용 예시
– let 또한 아래와 같이 정수 기반으로 사칙연산을 처리하지만 부동 소수점 연산을 지원하지 못한다.
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# let “A=1+1” && echo $A
2
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# let “A=1+1.5” && echo $A
-bash: let: A=1+1.5: syntax error: invalid arithmetic operator (error token is “.5”)
[root@s-node01 ~]#
[root@s-node01 ~]#
3. bc를 통한 부동 소수점 연산
– 다행이도 Linux 에는 부동소수점 연산 처리를 위해 bc 라는 명령을 제공하며 사용 예시는 아래와 같다.
[root@s-node01 ~]#
[root@s-node01 ~]# echo “1 + 1” | bc
2
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# echo “1 + 1.5” | bc
2.5
[root@s-node01 ~]#
[root@s-node01 ~]#
– 하지만 아쉽게도 bc에도 단점이 있으니 아래와 같이 미리 소수점 자리수 지정해 주지 않으면 값을 생략해 버린다.
[root@s-node01 ~]#
[root@s-node01 ~]# echo “20 / 1.5” | bc
13
[root@s-node01 ~]#
[root@s-node01 ~]# echo ’10 / 5′ | bc
2
[root@s-node01 ~]#
[root@s-node01 ~]# echo ’10 / 10′ | bc
1
[root@s-node01 ~]#
[root@s-node01 ~]# echo ’10 / 20′ | bc
0
[root@s-node01 ~]#
[root@s-node01 ~]# echo ‘scale=3;10 / 20’ | bc
.500
[root@s-node01 ~]# echo ‘scale=2;10 / 20’ | bc
.50
[root@s-node01 ~]# echo ‘scale=1;10 / 20’ | bc
.5
[root@s-node01 ~]#
4. awk 내장 연산자를 통한 처리
– awk 또한 아래와 같이 미리 소수점 처리에 대한 정의를 해줘야 한다.
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# echo “20 40” | awk ‘{printf “%.1f”, $1 / $2}’ && echo
0.5
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# echo “20 40” | awk ‘{printf “%.3f”, $1 / $2}’ && echo
0.500
[root@s-node01 ~]#
[root@s-node01 ~]#
5. 부동소수점 정수의 비교 연산을 적용한 MAX 함수 구현
– Bash 는 기본적으로 부동 소수점을 이해하지 못하기 때문에 Shell script의 if 구문 이하 비교 연산자로는 소수의 비교 연산을 처리 할 수가 없다.
때문에 MAX 함수등을 구현하기 위해서는 아래와 같이 bc등 부동 소수점을 이해하는 명령을 통해 값의 참 여부를 결과값으로 받아 로직을 구현해야한다.
#!/bin/bash
for LIST in `cat $1`
do
export DIFF=`echo “${LIST} > ${MAX}” | bc`
if [ “$DIFF” -eq 1 ];
then
MAX=${LIST}
fi
done
6. 상기 사항들을 적용한 Shell Script 예시 / 부동소수점연산 및 MAX 함수 구현
[root@s-node01 ~]#
[root@s-node01 ~]# head -10 list
2014-03-17 16:48:28 7.96 %
2014-03-17 16:49:28 7.96 %
2014-03-17 16:50:28 7.97 %
2014-03-17 16:51:28 7.97 %
2014-03-17 16:52:28 7.97 %
2014-03-17 16:53:28 7.97 %
2014-03-17 16:54:28 7.97 %
2014-03-17 16:55:28 7.97 %
2014-03-17 16:56:28 7.96 %
2014-03-17 16:57:28 7.97 %
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# cat test.sh
#!/bin/bash
RAWDATA=$1
cat ${RAWDATA} | cut -d “:” -f1 | uniq > uniq.list
while read UNIQ_LIST;
do
TOTAL_SUM=0
TOTAL_LIST=`cat ${RAWDATA} | sed ‘s#%##g’ | grep “^${UNIQ_LIST}”`
TOTAL_RAW=`cat ${RAWDATA} | sed ‘s#%##g’ | grep “^${UNIQ_LIST}” | awk ‘{print $3}’`
TOTAL_COUNT=`cat ${RAWDATA} | sed ‘s#%##g’ | grep “^${UNIQ_LIST}” | wc -l`
MAX=0
for LIST in ${TOTAL_RAW}
do
export TOTAL_SUM=`echo “${TOTAL_SUM} + ${LIST}” | bc`
export DIFF=`echo “${LIST} > ${MAX}” | bc`
if [ “$DIFF” -eq 1 ];
then
MAX=${LIST}
fi
if [ -z “$MIN” -a -z “$BEFOR_LIST” ];
then
MIN=${LIST}
BEFOR_LIST=${LIST}
else
export MIN_DIFF=`echo “${LIST} <= ${BEFOR_LIST}" | bc`
if [ "$MIN_DIFF" -eq 1 ];
then
MIN=${LIST}
fi
BEFOR_LIST=${MIN}
fi
done
export AVERAGE=`echo "${TOTAL_SUM} ${TOTAL_COUNT}" | awk '{printf "%.2f", $1 / $2}'`
echo -e "TIME=$UNIQ_LIST \t Average=${AVERAGE} \t Min=${MIN} \t Max=${MAX}"
unset MIN
unset BEFOR_LIST
done < uniq.list
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]# ./test.sh list
TIME=2014-03-17 16 Average=7.97 Min=7.96 Max=7.97
TIME=2014-03-17 17 Average=7.98 Min=7.96 Max=7.99
TIME=2014-03-17 18 Average=7.99 Min=7.96 Max=8
TIME=2014-03-17 19 Average=8.00 Min=7.96 Max=8.01
TIME=2014-03-17 20 Average=8.00 Min=7.96 Max=8.01
TIME=2014-03-17 21 Average=8.01 Min=7.96 Max=8.02
TIME=2014-03-17 22 Average=8.02 Min=7.96 Max=8.03
TIME=2014-03-17 23 Average=8.03 Min=7.96 Max=8.04
TIME=2014-03-18 00 Average=8.04 Min=7.96 Max=8.05
TIME=2014-03-18 01 Average=8.05 Min=7.96 Max=8.05
TIME=2014-03-18 02 Average=8.06 Min=7.96 Max=8.06
TIME=2014-03-18 03 Average=8.06 Min=7.96 Max=8.06
TIME=2014-03-18 04 Average=8.06 Min=7.96 Max=8.08
TIME=2014-03-18 05 Average=8.06 Min=7.96 Max=8.07
TIME=2014-03-18 06 Average=8.07 Min=7.96 Max=8.08
TIME=2014-03-18 07 Average=8.08 Min=7.96 Max=8.09
TIME=2014-03-18 08 Average=8.09 Min=7.96 Max=8.14
TIME=2014-03-18 09 Average=8.10 Min=7.96 Max=8.11
TIME=2014-03-18 10 Average=8.11 Min=7.96 Max=8.12
TIME=2014-03-18 11 Average=8.12 Min=7.96 Max=8.13
TIME=2014-03-18 12 Average=8.14 Min=7.96 Max=8.15
TIME=2014-03-18 13 Average=8.15 Min=7.96 Max=8.16
TIME=2014-03-18 14 Average=8.16 Min=7.96 Max=8.18
TIME=2014-03-18 15 Average=8.18 Min=7.96 Max=8.2
TIME=2014-03-18 16 Average=8.19 Min=7.96 Max=8.2
[root@s-node01 ~]#
[root@s-node01 ~]#
[root@s-node01 ~]#