- 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어
명령어: expr, test, ls
키워드: 윤년, 나머지
사용처: 2월 말에 작성된 로그 파일을 선택하고 싶을 때
실행예제
$ ./leapyear.sh
leap year: 2012
/var/log/myapp/access.log-20120229
스크립트
#!/bin/sh
# 네 자리 년도 얻기
year=$(date '+%Y') #--------------------------------------- 1
logfile="/var/log/myapp/access.log-"
# 년도를 나눈 나머지 계산
mod1=$(expr $year % 4) #----------------------------------- 2
mod2=$(expr $year % 100) #--------------------------------- 2
mod3=$(expr $year % 400) #--------------------------------- 2
# 윤년인지 판정
if [ $mod1 -eq 0 -a $mod2 -ne 0 -o $mod3 -eq 0 ]; then #--- 3
echo "leap year: $year"
ls "${logfile}${year}0229" #--------------------------- 4
else
echo "not leap year:$year"
ls "${logfile}${year}0228" #--------------------------- 5
fi
해설
이 스크립트는 2월 말일 파일을 표시하기 위해 올해가 윤년인지 판별합니다. access.log-20120315 처럼 파일명에 년월일이 있는 로그 파일이 /var/log/myapp 디렉터리에 저장되어 있다고 가정합니다.
월말에 로그 파일을 참조해서 월별 처리를 하는 일이 많을 겁니다. 예제처럼 파일명에 날짜가 적힌 로그 파일을 다룰 때 2월 말일인지 판단하는 것은 프로그래머의 공통된 고민거리입니다.
우선 윤년인지 판정하는 조건을 확인해봅시다.
- 서력이 4로 나눠 떨어지면 윤년
- 단, 100으로 나눠 떨어지면 윤년이 아님
- 단, 400으로 나눠 떨어지면 윤년
특히 세 번째 조건은 알 알려지지 않아서 2000년에 많은 버그가 발생했던 원인이 되기도 했습니다.
우선 1
에서 서력을 네 자리로 취득해서 셸 변수 year에 대입합니다. 2
에서 년도를 나눈 나머지를 expr 명령어로 계산합니다. expr 명령어로 % 연산자를 써서 나머지를 계산하는데 조건 1, 2, 3의 각 나머지 값을 셸 변수 mod1, mod2, mod3에 대입합니다.
3
에서는 앞에선 본 윤년 조건을 if문으로 판정합니다. 나눠 떨어진다라는 것은 나머지가 0이라는 뜻이므로 0과 변숫값을 비교합니다. 값이 같은지는 -eq 연산자로, 같지 않은지는 -ne 연산자로 판별합니다. -a는 AND, -o는 OR을 뜻합니다. 3
조건식은 “mod1 값이 0이고 mod2 값은 0이 아니다” 또는 “mod3이 0”이라는 조건을 뜻합니다. test 명령어의 수치 판정 연산자는 다음 표를 참조하기 바랍니다.
-
test 명령어 비교 연산자
표기 의미 변수1 -eq
변수2변수1과 변수2가 같으면 참 변수1 -ne
변수2변수1과 변수2가 다르면 참 변수1 -lt
변수2변수1이 변수2 미만이면 참 변수1 -le
변수2변수1이 변수2 이하이면 참 변수1 -gt
변수2변수1이 변수2 초과면 참 변수1 -ge
변수2변수1이 변수2 이상이면 참
lt는 “less than”, le는 “less than or equal to”, gt는 “greater than”, ge는 “greater than or equal to”입니다.
이렇게 하면 윤년 판정이 되므로 2월 말일 파일을 선택할 수 있습니다.
4
와 5
에서 윤년일 때는 2월 29일 로그 파일을, 윤년이 아니면 2월 28일 로그 파일을 ls 명령어로 표시합니다.
주의사항
- test 명령어의 -a(AND)와 -o(OR) 연산자 우선 순위는 다른 프로그래밍 언어와 마찬가지로 AND가 OR보다 우선입니다. 만약 OR 우선도를 AND보다 높이고 싶으면 괄호로 둘러쌉니다. 이때 셸이 괄호를 해석하지 않도록 \로 이스케이프해서 (… )처럼 사용합니다.
# 앞에 있는 -a(AND)보다 -o(OR)가 우선 처리됨 if [ $a -eq 0 -a \ ( $b -ne 0 -o $c -eq 0 \) ]; then
“$a가 0이고, 4b가 0이 아니거나 $c가 0”일 때 참이 됩니다. test 명령어는 셸 내장과 외부 명령어 두 종류가 있는데 셸 스크립트는 셸 내장 test 명령어가 사용됩니다. 따라서 man sh로 셸 매뉴얼을 보면 test 명령어 설명이 나옵니다.