티스토리 뷰

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

 

 

반응형
댓글
댓글쓰기 폼