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,]라고 적으면 이런 문제를 피할 수 있습니다.
참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전
'IT 이야기 > Linux 셸 스크립트' 카테고리의 다른 글
[Linux 셸 스크립트] 텍스트 처리 - 075 숫자값(CSV 파일)에서 "*"를 써서 간단한 텍스트 그래프 출력하기 (0) | 2021.04.09 |
---|---|
[Linux 셸 스크립트] 텍스트 처리 - 074 숫자로 된 CSV 파일에서 평균값 계산하기 (0) | 2021.04.09 |
[Linux 셸 스크립트] 텍스트 처리 - 072 CSV 파일에서 지정한 특정 레코드의 컬럼값 얻기 (0) | 2021.04.08 |
[Linux 셸 스크립트] 텍스트 처리 - 071 입력 파일 해시값을 줄마다 추가해서 출력하기 (0) | 2021.04.08 |
[Linux 셸 스크립트] 텍스트 처리 - 070 파일 앞머리의 셔뱅(shebang, #!/bin/sh 등)을 추출해서 스크립트에 따라 확장자 붙이기 (0) | 2021.04.07 |
댓글