이전 글에 이어 출퇴근 체커 만들기. 내가 혹시 뻘짓을 하고 있는게 아닌지 (맞긴 하지만) 확인 차 다른 동료들에게 물어봤다. 카카오톡PC버전 로그인 메세지 시간, 시간 기록용 앱, 옆사람에게 물어보기, 뇌피셜 등 다양한 방법을 통해 출근 시간을 기록하고 있었다.

ShellScript 문법을 알아볼 겸 필요해서 만들어보는 출퇴근 기록기 예제 2탄.

오늘의 목표 : 출근 후 맥을 켜면 자동으로 Slack에 출퇴근 시간 메세지 보내기


Mac 터미널에서 Slack에 메세지 보내기(1) 포스트에서는 sh 파일 생성, 실행 및 변수 선언, 반복문, 함수 사용법을 간단히 익혔다. 또 Slack Webhook 기능을 이용해 맥 Terminal에서 Slack으로 json 형태의 메세지를 보내는 방법까지 알아보았다. 보내고 싶은 메세지(출퇴근 시간 기록)를 조금 더 가공하고 싶어 이번에는 ShellScript 문법을 조금 더 알아보는 데에 초점을 두었다.

ShellScript 문법

  • if 조건문
  • 현재 시각 구하기
  • String 가공하기

if 조건문

여타 코드에서 볼 수 있는 if문과 비슷하게 생겼다. if조건에 부합하면 then을, 그리고 맨 끝에 fi를 써주어야 한 다는게 차이점이었다.

if [ ... ]
then
  # run if code
elif [ ... ]
then
  # run else-if code
else
  # run else code
fi


세미콜론(;)을 이용해 라인을 끝내고 then을 바로 붙여 가독성을 높이는 방식으로도 많이 쓰이는 것 같다.

if [ $result = "true" ]; then
  # this will be run
fi


여기까진 괜찮았는데, 충격적이었던 부분은 띄어쓰기를 틀리면 코드가 제대로 동작하지 않는다는 점이었다. 대괄호, 등호 사이에 띄어쓰기가 들어가야 하는 것 같다.

if [$result = "true" ]
    # this won't be run
fi


또 주의해야 할 점은, 어떤 shell에서는 String 비교에 ==를 허용하긴 한다. 그렇지만 보통의 경우에는 = 혹은 -eq를 사용해 비교를 한다.


현재 시각 구하기

ShellScript 에서는 $(date)를 이용해 현재 시각을 구할 수 있다.

time=$(date)
echo $time

# or
echo $(date)

# Wed Apr 1 20:59:13 KST 2020


String 가공하기

공백제거

tr -d를 사용해 공백을 제거한다.

str=" When will Corona end?"

noSpaceStr=$( echo -e $str | tr -d '[:space:]' )

echo $noSpaceStr

# WhenwillCoronaend?

코로나는 진짜 언제 끝나나요.


문자열 나누기

다시 last reboot의 가장 첫 로그를 가져와보자.

timeLog=$(last reboot | head -n 1)
echo $timeLog

# reboot    ~                         Wed Apr  1 19:40

reboot, ~, Wed, Apr, 1, 19:40 으로 구성된 라인을 쪼개서 사용해야 할 때 read를 사용한다. 콘솔에서 입력을 받을 수도 있지만, $timeLog와 같은 변수를 직접 입력해서 쓸 수 있는 것 같다. read 다음에는 변수 이름을 자유롭게 적어준다.

read rebootStr tilde day month date time <<< $timeLog

echo "rebootStr : $rebootStr"
echo "tilde : $tilde"
echo "day : $day"
echo "month : $month"
echo "date : $date"
echo "time : $time"


# rebootStr : reboot
# tilde : ~
# day : Wed
# month : Apr
# date : 1
# time : 19:40


일부 문자열 가져오기

Substring과 비슷한 기능이다. String에서 시작하는 position과 개수를 지정하면 해당 문자열만 가져올 수 있다.

19:40 이라는 문자열에서 앞의 두 글자를 가져오려면 0번째부터 2개를 가져오고(0,1번 인덱스), 뒤의 두 글자를 가져오려면 3번째부터 2개를 가져오기 때문에(3,4번 인덱스) 아래와 같이 사용할 수 있다.

time="19:40"

hour=${time:0:2}
minute=${time:3:2}
echo $hour
echo $minute

# 19
# 40



출퇴근 시간 예쁘게 기록하기

예쁜 출퇴근 체커를 만들기 위해선 몇 가지 조건들이 더 필요했다.

  • 그 날의 최초 부팅 시각만 출근 시간으로 인정할 것
  • ‘출근 시간 +9’ 를 계산해서 퇴근 시간을 알려줄 것
  • 평일에만 슬랙 메세지를 보낼 것


last reboot 의 가장 최근 기록을 사용하면 컴퓨터를 두 번 부팅한 날에는 출퇴근 시간이 꼬일 수 있다. 그래서 최근 10개의 부팅 기록을 가져오고, 한 줄 씩 읽어가며 오늘의 날짜와 비교하는 작업이 필요했다.

10개까지만 for 문을 돌면서 오늘의 날짜와 체크하고, 만약 오늘 날짜에 해당하는 기록이 없을 경우에는 기록이 없다는 메세지를 슬랙으로 보낼 것이다. 그래서 우선 오늘의 날짜와 일을 구하고 부팅정보를 기록할 변수를 만들었다.

recent10=$(last reboot | head -n 10)

today=$(date)
todayDay="$(echo -e "${today:8:2}" | tr -d '[:space:]')"
todayStartTime="부팅 정보가 없습니다."


reboot 기록을 한 줄씩 가져오는 방법으로는 무식하게 캐릭터 54자씩 잘라서 사용했다. 최신 순으로 한 줄만 read해서 날짜를 가져오고, 오늘의 날짜와 같으면 그 부팅 로그를 다른 변수에 저장했다.

for i in {1..10}
do
    timeLog=${recent10:$(($i-1))*54:54}
    read no1 no2 A month date time <<< $timeLog
    if [ $todayDay = $date ]; then
        todayStartTime=$timeLog
    fi
done


그 다음에는 ‘부팅 정보가 없습니다.’ 또는 오늘의 최초 부팅 로그를 슬랙 메세지를 보내기 위해 json 형식으로 바꾸어주었다.

if [[ "$todayStartTime" =~ "부팅 정보가 없습니다." ]]; then
    json="{\"text\": \"$todayStartTime\"}"
else
    read no1 no2 day month date time <<< $todayStartTime
    hour=${time:0:2}
    minute=${time:2:3}
    gotime="$(($hour+9))$minute"

    msg="$month $date($day)

Start: $time
End  : $gotime"

    json="{\"text\": \"$msg\"}"
fi


마찬가지로 요일도 String 값에서 가져와 원시적인 방법으로 비교를 해 평일에만 슬랙 메세지를 보내도록 만들었다.

if [[ $day == "Mon" || $day == "Tue" || $day == "Wed" || $day == "Thu" || $day == "Fri" ]]; then
    curl -X POST -H 'Content-type: application/json' --data "$json" $my_slack_webhook
fi


Crontab 으로 부팅 시 sh 자동 실행하기

매일 스크립트 파일을 수동으로 실행해주면 의미가 없으니 자동으로 돌리도록 하자.

우선 sh 파일을 실행 가능하게 만들기 위해 chmod를 사용한다.

chmod +x directory/of/your/shellscript.sh


이제 터미널에서 새 크론탭을 작성한다.

crontab -e


새로운 파일이 vi로 열린다. 이곳에서 sh 파일을 실행해주는 명령을 작성한다.

@reboot zsh ~/dev/workingcheck.sh

i를 눌러 INSERT 모드일 때 명령어를 입력하고, esc를 누른 후 :wq를 입력하면 변경 사항이 저장된다. 그러면

crontab: installing new crontab

이라는 문구가 뜨며 설치가 완료된다.

다음 번 부팅 시 자동으로 슬랙 메세지를 보낸다. 로그인 화면도 아니고 사과 떠 있는 검은 화면에서 메세지 보내는 건 조금 신기하다.



결론

나는 맥북을 매일 켜고 끄는데, 대다수 사람들은 그냥 sleep 만 걸어놓고 퇴근하는 것 같다. last reboot가 아닌 그냥 last 명령어를 사용해 그날의 최초 사용 시간을 확인하면 매일 컴퓨터를 끄지 않아도 확인할 수 있을 것 같다. 그리고 일일이 sh 파일을 옮기고 crontab 세팅을 하지 않고 install 방식으로 한큐에 진행하고 싶었는데, 방법을 몰라 답답했다. 나 쓰기엔 편하지만 뭔가 완전하게 만족스럽지는 않은 결과물이다. 나중에 더 공부해서 꼭 알아내고 싶다.

요즘 출근 시간이 죄다 10시다 일찍 좀 일어나자. 9시 칼출근해서 회사 불 켜던 때로는 못 돌아가도 9시 반에는 오자.


References

  • https://www.shellscript.sh/