텍스트처리_08 숫자값(CSV 파일)에서 "*"를 써서 간단한 텍스트 그래프 출력하기

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

명령어: echo, awk, sort, head, expr, read
키워드: 그래프, CSV 파일, 최대값
사용처: 숫자 자료를 간단히 텍스트 그래프로 표시하고 싶을 때


실행예제

$ ./csv-graph.sh data.csv
****** [Kim]
************************************************ [Lee]
**************** [Park]
 [Kang]
 ************ [Seo]

스크립트

#!/bin/sh

csvfile="data.csv"  # 자료 CSV 파일 ----------------- 1
GRAPH_WIDTH=50  # 그래프 너비 ------------------------1

markprint() {  #------------------------------------ 2
  local i=0  #-------------------------------------- 3
  while [ $i -lt $1 ]  #---------------------------- 4
  do
    echo -n "*"  #---------------------------------- 5
    i=$(expr $i + 1)
  done
}

# 자료에서 최댓값 얻음. 역순 정렬해서 첫 줄 얻음
max=$(awk -F, 'print $3' "$csvfile" | sort -nr | head -n 1)  #--- 6

# 자료가 모두 0이면 최댓값을 1로 지정
if [ $max -eq 0 ]; then  # ---------------------------------------7(if문)
  max=1
fi

# CSV 파일을 읽어서 값마다 그래프 출력 ----------------------------- 8
while IFS=, read id name score
do
  markprint $(expr $GRAPH_WIDTH \* $score / $max)  #------------- 9
  echo " [$name]"
done < $csvfile

   

해설

이 스크립트는 명령행 인수로 지정한 CSV 파일 점수값을 “*“를 사용해 텍스트 그래프로 출력합니다.

그래픽 그래프를 엑셀 등으로 작성하는 경우가 많은데, 태겍스트 그래프 역시 메일 본문이나 터미널에서 상태를 보는 용도로 이전부터 자주 사용됐습니다.

아래 CSV파일(data.csv)의 형식은 “ID번호, 이름, 점수”입니다.

  • 파일1 CSV파일(data.csv)
    0001,Kim,45
    0002,Lee,312
    0003,Park,102
    0004,Kang,3
    0005,Seo,92
    

우선 1에서 스크립트를 초기화합니다. 셸 변수 csvfile에는 입력한 csv 파일명을, 셸 변수 GRAPH_WIDTH에는 그래프 폭을 설정합니다.   2에서는 텍스트 그래프를 출력하는 셸 함수를 정의합니다. 함수는 숫자를 하나 받아서 그 개수만큼 “*“를 표시하는 함수입니다. 함수 인수는 셸에서 $1에 대입됩니다.   3은 카운터 변수를 지역변수로 초기화 합니다.
4는 함수 인수 $1보다 카운터가 작으면 "*"를 계속 출력합니다. 그리고 "*"을 출력할 때는 echo 명령어 -n 옵션을 사용해서 줄바꿈 없이 출력합니다 5.
**echo 명령어 -n 옵션
은 Mac에서는 에러가 발생하므로 주의사항을 확인하기 바랍니다.   6은 CSV 파일에서 미리 최대값을 취득하는 처리입니다. 텍스트 그래프를 작성할 때는 폭을 구해서 그 안에 들어가도록 해야 합니다. 따라서 우선 자료 최대값을 취득해서 그 너비안에 들어가게 합니다.   CSV의 특정 열에서 최대값을 취득하려면

  1. 그 컬럼값을 1열에 표시
  2. sort 명령어 -nr(숫자로 정렬 및 역순 정렬) 옵션으로 정렬
  3. head 명령어로 첫 줄만 취득

순서대로 처리하면 최대값을 얻습니다. 6에서 이 처리를 수행합니다. 우선 awk 명령어 구분자로 -F,로 쉼표를 지정하고, 세 번째 컬럼을 {print $3}으로 표시합니다. 이걸 파이프로 sort 명령어에 넘겨서 -nr 옵션으로 숫자 역순 정렬합니다. 마지막으로 head 명령어 지정 줄 수를 취득하는 -n 옵션으로 1을 지정하고 첫 줄을 추출합니다. 이걸로 CSV 파일 점수값 중 최대값을 셸 변수 max에 대입할 수 있습니다.

76에서 얻은 최대값이 0이면 셸 변수 max에 1을 설정합니다. 그래프 폭 계산에서는 최대값으로 나누기를 하므로 그대로 0을 쓰면 에러가 발생하기 때문입니다.

이걸로 그래프르르 그릴 준비가 되었으므로 8과 같이 CSV 파일에서 순서대로 자료를 읽어 그래프를 그립니다. 또한 IFS에 임시로 쉼표를 설정해서 셸 변수 id, name, score에 값을 넣습니다.   9는 텍스트 그래프를 출력하는 markprint 함수에 "*" 출력 개수를 넘깁니다. score 숫자를 그대로 지정하면 너비를 넘을 수도 있으므로 정규화를 위해 최대값 max로 나눈 값을 expr 명령어로 계산해서 그 값을 markprint 함수에 전달합니다. 이렇게 하면 너비를 최대로 사용한 그래프를 출력할 수 있습니다.

그리고 markprint 함수는 *를 출력할 뿐 줄바꿈하지 않습니다. 따라서 9 다음에 CSV 파일 두 번째 컬럼(이름 컬럼)에서 추출한 값이 셸 변수 name에 저장되어 있으므로 * 오른쪽에 [$name]으로 표시합니다.

이렇게 줄마다 필요한 개수만큼 *를 출력해서 텍스트 그래프를 그립니다.

   

주의사항

  • 이 스크립트는 세 번째 점수값은 expr 명령어로 나눗셈을 하므로 정수에만 대응합니다.

  • 5에서 사용하는 echo -n은 Mac에서는 사용할 수 없습니다.