사부작사부작해요

쉘스크립트로 알고리즘 문제 풀이 파일 관리 자동화 본문

알고리즘/문제풀이

쉘스크립트로 알고리즘 문제 풀이 파일 관리 자동화

sabujaky 2022. 9. 12. 04:05
 

GitHub - yuna1212/coteto: 알고리즘 문제 풀이 파일 관리 - 파일 생성 및 시간 기록

알고리즘 문제 풀이 파일 관리 - 파일 생성 및 시간 기록. Contribute to yuna1212/coteto development by creating an account on GitHub.

github.com


코테 알고리즘 문제를 풀 때, 나만의 기록용 주석을 파일의 맨 앞에 작성한다.

기록용 주석은 시작 시간, 소요 시간, 풀이 방법을 정해둔 양식으로 작성한다.

 

근데 이걸 매번 작성하기 귀찮아서, 양식에 맞게 파일을 생성·수정해주는 bash 쉘 스크립트를 작성하고 환경 변수에 등록해줬다.

매번 직접 작성한 readme와 문제 풀이 파일. 사진 클릭하면 github 보러갈 수 있다.

지금까지 작성한 기록을 보니, 소요 시간(풀이 시간)은 대개 10분을 단위로 계산했었다.

시작 시간과 소요 시간을 주석에 직접 기록하는 것도 귀찮았지만, 계산한 소요시간을 복사해서 리드미에 붙여넣는 것 역시 귀찮았다.

 

프로그램을 작성하기 앞서, 이런 문제를 해결하기 위한 요구사항을 도출했다.

1. 프로그램 요구사항

1. 사용자가 입력한 이름의 문제 풀이 파일을 양식에 맞게 생성

  • 문제 풀이 파일은 python 파일만 허용
  • 동일한 이름의 파일이 존재하는 경우, 파일 생성 불가
  • 시작 시간으로 현재 시간의 년, 월, 일, 시각(시간, 분)을 파일에 기록
  • 소요 시간과 풀이 방법법의 내용은 빈칸으로 두기
  • 양식에 맞게 생성한 파일을 vi로 바로 열어주기

2. 소요 시간을 현재 시간과 문제 풀이 파일의 시작 시간 기준으로 계산하고 파일에 작성

  • 소요 시간은 10분 단위로 반올림하여 계산: 지금까지 작성한 기록 토대로, 10분 단위로 계산하기로 결정!
  • 계산한 소요시간은 프롬프트에 출력: readme에 붙여넣기 쉽게!
  • 문제 풀이 파일에 소요 시간을 양식에 맞게 기록
  • 소요 시간이 기록되어 있다면, 무시하고 덮어쓰기

2. 코드

요구사항 1을 만족하는 cote-init.sh와 요구사항 2를 만족하는 cote-fin.sh를 작성했다.

혹시 나중에 막 만지다가 망가질까봐 소유자를 root로 바꾸고 권한도 644로 최소화했다.

cote-init.sh

#!/bin/bash

# argument 개수 체크
if [ $# -lt 1 ]
then
    echo "err: 첫번째 argument로 파일 이름이 필요합니다."
    exit
fi

# 사용자가 입력한 파일명이 python 파일인지 체크
file_name=$1
if [[ ! $file_name =~ \.py$ ]]
then
    echo "err: 파일의 확장자는 반드시 .py 여야 합니다"
    exit
fi

# 기존에 같은 이름의 파일이 존재하는지 체크
find_file_command="ls -a | grep '$file_name'"
find_result=$(eval "$find_file_command")
is_exist=${#find_result}
if [ $is_exist -gt 0 ]
then
    echo "err: 동일한 이름의 파일이 이미 존재합니다."
    exit
fi

# 기록할 현재 시간 가져오기
now=`date +'%F %I:%M %p'`
echo $now

# 현재 시간을 새로운 파일에 기록하고 vi로 열기
template="\"\"\"\n시작 시간: $now\n소요 시간: \n풀이 방법:\n\"\"\"\n"
echo -e "$template" > "$file_name"
vi + "$file_name"

cote-fin.sh

#!/bin/bash

# argument 체크
if [ $# -lt 1 ]
then
    echo "err: 첫번째 argument로 파일 경로가 필요합니다."
    exit
elif [ $# -gt 1 ]
then
    echo "err: 하나의 argument만 가능합니다. 또한 argument는 유일한 파일의 경로여야 합니다."
    exit
fi

file_name=$1

# 기록할 현재 시간 가져오기
now_time=`date +'%F %I:%M %p'`
echo "현재 시간: $now_time"

# 파일에서 시작 시간 읽어오기
start_time_line=$(sed -n 2p "$file_name")
start_time=$(echo $start_time_line | grep -oP '(19|20)\d{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]) (0[1-9]|1[012]):[0-5][0-9] [AP]M')
echo $start_time_line

# 시작 시간에서 현재 시간 빼기
now_sec=$(date -d "$now_time" +%s)
start_sec=$(date -d "$start_time" +%s)
sec_diff=$(($now_sec-$start_sec))
min_diff=$(($sec_diff/60))
hour_diff=$(($min_diff/60))
min_diff=$(($min_diff%60))
echo "소요 시간: $hour_diff시간 $min_diff분"

# 뺀 시간만큼을 포매팅하고 echo
consumed_time_format="-분"
min_apprx=$((($min_diff+5)/10*10))
hour_apprx=$((hour_diff+$min_apprx/60))
if [ $hour_apprx -eq 0 ]
then
    consumed_time_format="$min_apprx분"
elif [ $min_apprx -eq 0 ]
then
    consumed_time_format="$hour_apprx시간"
else
    consumed_time_format="$hour_apprx시간 $min_apprx분"
fi

echo -e "기록한 시간: \e[1;93m$consumed_time_format\e[0m"

# 파일에 소요 시간 기록
sed -i "3s/.*/소요 시간: $consumed_time_format/" "$file_name"

3. 실행 결과

cote-init으로 cote-init.sh를, cote-fin으로 cote-fin.sh를 실행하도록 환경 변수를 등록했다.

시작 시간과 소요 시간을 주석에 자동으로 기록한다. 소요 시간은 프롬프트에서 노란 글씨로 확인할 수 있다.

스크립트를 모두 실행하고, 주석에 내용이 잘 작성되었는지를 확인했다.
예외 처리도 보여주는 실행 결과

4. 후기

VSCode로 문제 풀 땐 양식 복붙해서 사용하는게 번거롭지 않았다. vi 쓰니까 귀찮아졌다.

근데 오히려 스크립트 작성해두고 사용하니까 VSC 쓰는 것 보다 훨씬 편해졌다!

 

소요 시간이 파일에 제대로 기록이 안되는 문제가 있었다. 실행 인자로 애스터리스크가 포함된 문자열을 넘길 때 발생하는 문제였다. 파일 이름이 길 때 애스터리스크를 종종 사용하는데, 스크립트의 인자로 애스터리스크가 포함된 문자열을 넘기면 ls의 결과가 넘어가더라.. 예상 못했던 부분이어서 해결하는데 시간이 좀 걸렸다.

 

예전에 교수님께서 코드를 한 화면에서 볼 수 없는 경우는 파일을 분리해서 짧게 작성하라고 말씀하셨었는데, 그런점에서 이번에 작성한 두 파일은 모두 적당해서 만족스럽다. 사실 예외처리를 내가 실수할 것 같은 것 위주로 최소화한게 코드가 짧은 이유이기도 하다. 

 

띄어쓰기 주의하는 것, if - fi 구조로 분기문 작성하는것이 어색했다. 하지만 리눅스 커맨드 쓰면서 단순하게 작성하고, 정규식도 쓰면서 재밌게 작업했다.


REFERENCES

 

Doing Date Math on the Command Line, Part I | Linux Journal

If you've ever used a spreadsheet, you've probably used or seen functions for doing date math—in other words, taking one date and adding some number of days or months to it to get a new date, or taking two dates and finding the number days between them.

www.linuxjournal.com

Comments