bash_03 사칙 연산을 간단하게 작성하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: echo
키워드: 산술식, 산술 확장, 산술 평가
사용처: expr 명령어를 사용하지 않고 산술식을 계산한 결과를 얻고 싶을 때


실행예제

$ ./bash-arithmetic.sh
	1.txt에서 100.txt 까지 100개의 파일이 작성됨

스크립트

#!/bin/bash

# 브레이스 확장으로 1에서 100까지 숫자 목록 생성
for i in {1..100}  #---------------------------- 1
do
  # 산술 확장을 이용해서 파일명에 3을 곱해서 계산한
  # 값을 텍스트 파일에 저장
  echo $((i * 3)) > ${i}.txt  #----------------- 2
done

   

해설

이 스크립트는 1에서 100가지의 파일명을 가진 파일을 작성합니다. 파일 내용은 파일명 숫자에 3을 곱한 값입니다. 어떤 테스트 파일을 대량으로 만들고 싶을 때 사용하면 유용합니다.

우선 1에서 브레이스 확장을 이용해서 1에서 100까지 숫자 목록을 만듭니다.

2에서 bash 고유 기능인 산술 확장(Arithmetic Expansion)을 이용합니다. 이 방법은 $((산술식))이라고 하는데, 괄호 안 산술식을 계산해서 그 결과를 숫자로 확장하는 표기법입니다. 이 산술식은 변수명 앞에 있는 $ 기호를 생략할 수 있습니다. 산술 확장은 일반적으로 sh 셸 스크립트에서 expr 명령어로 계산한 부분을 치환하는 목적으로 이용됩니다.

산술 확장에서 자주 사용하는 연산자는 다음과 같습니다. 자바나 C 언어에서 이용하는 연산자와 거의 같으므로 어렵지 않을 것입니다.

연산자 설명
+ 덧셈
- 뺄셈
* 곱셈
/ 나눗셈(버림)
% 나머지
** 제곱
« 왼쪽 쉬프트(비트 연산)
» 오른쪽 쉬프트(비트 연산)

산술 확장은 expr 명령어와는 달리 외부 명령어를 이용하지 않고 게산하여 속도가 무척 빠릅니다. 또한 변수명에 $가 필요 없으므로 곱셈 연산자 *를 이스케이프하지 않아도 되어 작성하기 편리합니다.

  • expr 명령어와 산술 확장의 차이점

    result=$(expr $i \* $i)   <-- expr 명령어는 곱셈 기호에 이스케이프 필요
    result=$((i * i))         <-- 산술 확장은 $과 이스케이프 불필요
    

그리고 산술 확장과 비슷한 예로 산술 평가(Arithmetic Evaluation)가 있습니다. 이것은 산술식을 평가해서 그 참과 거짓을 돌려줍니다. 따라서 if문이나 while문 조건식으로 test 명령어 대신에 사용하는 경우가 많습니다. 또한 증감/차감 연산자는 대입 연산 없이 단독으로도 사용할 수 있습니다. 연산 결과를 돌려주지 않아서 산술 확장보다는 산술 평가로 이용하는 것이 일반적입니다.   다음은 산술 평가를 이용해서 while 반복문을 작성하는 예입니다. expr 명령어를 사용하지 않으니 셸 스크립트 특유의 번잡함이 줄어드는 걸 알 수 있습니다.

  • 파일1 산술 평가를 사용하는 반복 처리

    #!/bin/bash
    
    # i=1에서 9까지 while 반복 처리
    i=1
    while ((i < 10))
    do
        어떤 처리
        ((i++))
    done
    

이렇듯 bash 산술 확장, 산술 평가를 이용하면 다양한 수치 계산을 간단히 작성할 수 있습니다. 또한 expr 명령어 오버헤드도 없어져서 스크립트가 빨라지는 것도 기대할 수 있습니다.

   

주의사항

  • 산술 확장은 변수 앞 $ 기호를 생략할 수 있는데 예외적으로 인수를 나타내는 위치 파라미터($1, $2 등)만 $ 기호를 생략하면 예를 들어 $1은 1이 되어서 숫자와 구분이 가지 않기 때문입니다.

  • 산술 평가에는 let 명령어를 이용하는 방법이 있습니다. 다음처럼 let 명령어 인수에 산술을 넘기면 산술 평가 표기법(())과 마찬가지로 산술식이 실행되어서 참/거짓 값이 돌아옵니다. 다음 두 줄은 같은 의미입니다.

    ((i++))
    let 'i++'
    
  • 셸 변수를 declare문 -i 옵션으로 정의하면 대상 변수는 $(()) 표기법을 사용하지 않아도 산술 확장을 이용할 수 있습니다.