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 ~]# |