[Linux 셸 스크립트] 텍스트 처리 - 073 CSV 파일에 ID 목록을 입력해서 대응하는 ID 컬럼값 얻기
본문 바로가기
IT 이야기/Linux 셸 스크립트

[Linux 셸 스크립트] 텍스트 처리 - 073 CSV 파일에 ID 목록을 입력해서 대응하는 ID 컬럼값 얻기

by 찬찬이 아빠 2021. 4. 8.
반응형
  1. 사용 명령어

(1) read

(2) grep

 

  2. 키워드 & 사용처

(1) 키워드

IFS, CSV, 레코드, 컬럼, 구분자, 분할

 

(2) 사용처

ID 목록 파일과 CSV 파일에서 지정한 ID의 컬럼값을 표시하고 싶을 때 사용합니다.

 

  3. 실행 예제
$ cat data.csv         <- CSV 파일 확인
0001,Kim,45
0002,Lee,312
0003,Park,102
0004,Kang,3
0005,Seo,92

$ cat id.lst        <- 입력 ID 파일 확인
0003
0004

$ ./csv-list.sh id.lst             <- ID 목록과 일치하는 이름 표시
Park
Kang

 

 

  4. 스크립트

#!/bin/sh

 

filecheck()

{

    if [ ! -f "$1" ]; then             

        echo "ERROR: File $1 does not exist." >&2             

        exit 1;                           

    fi

}

 

# CSV 파일명과 ID 목록 파일명으르 지정해서 파일 존재 확인

csvfile="data.csv"               

idlistfile="$1"                     

filecheck "$csvfile"           

 

filecheck "$idlistfile"

 

while IFS=, read id name score             

do

    grep -xq "$id" "$idlistfile"               

    if [ $? -eq 0 ]; then           

        echo $name

    fi

done < "$csvfile"

 

 

  5. 해설

이 스크립트는 ID 목록 파일을 명령행 인수로 지정해서 CSV 파일에서 일치하는 ID 컬럼값을 취득합니다. 대상 CSV 파일은 다음처럼 "ID번호, 이름, 점수" 형식이라고 가정합니다.

<data.csv 파일 내용>
0001,Kim,45
0002,Lee,312
0003,Park,102
0004,Kang,3
0005,Seo,92

 

ID 목록 파일은 추출하고 싶은 ID가 적힌 텍스트 파일입니다.

<id.lst> 파일 내용
0003
0004

 

예제에서는 IFS를 ,(쉼표)로 설정해서 read 명령어로 CSV 파일을 다룹니다.

 

에서 셸 변수 csvfile에 CSV 파일명을 설정하고, 셸 변수 idlistfile에 ID 목록 파일명을 설정해서 파일 존재를 확인합니다. 존재 확인은 셸 함수 filecheck()로 처리합니다.

 

에서 셸 변수 filecheck()는 test 명령어 -f 연산자(대상이 일반 파일인지 확인)를 사용해서 대상 파일을 확인합니다. 부정 연산자 !를 사용해서 대상이 디렉터리이거나 파일이 존재하지 않으면 에러를 표시하고 종료합니다.

 

에서 CSV 파일에서 셸 변수 id, name, score에 대응하는 값을 읽습니다. 이 처리를 위해 임시로 환경 변수를 설정하고 명령어를 실행하는 방법을 설명합니다. 예제에서는 일시적으로 설정하는 환경 변수로 IFS를 사용합니다.

# 일시적으로 환경 변수를 설정해서 명령어는 실행하는 예
$ TMPDIR=/mytmp ./start.sh

 

환경 변수 TMPDIR을 임시로 설정해서 start.sh를 실행합니다. 이 줄 다음부터 환경 변수 TMPDIR에 설정한 값은 원래 설정한 값이 되어서 /mytmp가 아니게 됩니다. 즉, "환경 변수=값 명령어"는 어떤 특정 명령어나 스크립트를 실행할 때만 일시적으로 환경 변수를 설정하게 됩니다.

 

에서 while문 조건식은 다음과 같습니다.

IFS=, read id name score

즉, 임시로 환경 변수 IFS를 ,(쉼표)로 설정해 read 명령어를 실행합니다. 여기서 id, name, score는 셸 변수입니다.

 

환경 변수 IFS에 쉼표를 임시로 설정하면 셸이 해석하는 구분자를 쉼표로만 지정할 수 있습니다. 이러면 쉼표로 나뉜 줄을 분해해서 각각 셸 변수에 대입하게 됩니다.

 

에서 지정한 while문을 정리하면 "셸 변수 csvfile로 지정한 CSV 파일에서 한 줄씩 읽어서 read 명령어를 사용해서 셸 변수에 값을 대입합니다. 이때 값의 구분자는 환경 변수 IFS에 ,(쉼표)를 설정해서 쉼표로 구분합니다. 이렇게 하면 쉼표로 줄을 분할해서 각각의 컬럼값이 셸 변수 id, name, score에 대입된다."라는 뜻이 됩니다. 조금 복잡하지만 이런 방법은 CSV 파일을 다룰 때 자주 사용하는 방법이므로 잘 이해하기 바랍니다.

 

에서 ID 목록 파일의 ID와 CSV 파일의 ID가 일치하는지 확인하기 위해 grep 명령어의 -x 옵션과 -q 옵션을 사용합니다. grep 명령어 -x 옵션은 한 줄 전체가 패턴과 완전 일치할 때만 선택하는 옵션입니다. grep으로 "0001"이라는 ID로 검색하면 "00010"이라는 ID도 찾아서 파일에서 ID를 검색할 때 잘못된 결과를 출력할지도 모릅니다. CSV 파일에서 추출한 ID가 ID 목록 파일과 완전 일치하는지 확인하기 위해 -x 옵션을 사용하는 것입니다.

 

또한 에서 일치하는지 여부만 종료 스테이터스로 확인하므로 grep 명령어 검색 결과를 출력하지 않는 -q 옵션을 사용합니다.

 

⑤에서 grep 명령어 종료 스테이터스를 판단해서 일치 여부를 확인합니다. 일치하면 종료 스테이터스 $?가 0이 되므로 if문에서 판정해서 참일 때 CSV 파일에서 추출한 이름(셸 변수 name)을 echo 명령어로 표시하면 해당 ID의 이름을 추출할 수 있습니다.

 

 

<주의사항>

값 자체에 쉼표가 포함된 파일은 이 스크립트에서 다룰 수 없습니다.

예제처럼 이름만 추출해서 표시하는게 아니라 단순히 ID와 일치하는 줄 전체를 표시하고 싶을 때 아래와 같이 grep 명령어의 -f 옵션을 사용합니다.

$ grep -f id.lst data.csv
0003,Park,102
0004,Kang,3

하지만 이 예제에서는 id.lst 파일에 [0001]이 있으면 [00010]이라는 ID와 일치하게 됩니다. 또한, 만약 이름이 [0001 Song]인 경우에도 일치하게 됩니다. 이럴 때 ID 목록 파일 첫 글자에 ^를 붙이고 ID 끝에 ,를 붙인 [^0001,]라고 적으면 이런 문제를 피할 수 있습니다.

 

 

 

참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전

반응형

댓글