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

서진우

슈퍼컴퓨팅 전문 기업 클루닉스/ 상무(기술이사)/ 정보시스템감리사/ 시스존 블로그 운영자

You may also like...

2 Responses

  1. 2022년 6월 18일

    1minnesota

  2. 2023년 1월 27일

    2respectively