리눅스에서 텍스트파일 조인하기
리눅스 코맨드로 csv 2개를 결합하는데 특정 컬럼의 값을 기준으로 조인해서 붙이고 싶을 때가 있습니다.
DB에서 SQL로 조인하는 것처럼 하는 것 말입니다.
리눅스에서 이런 것은 오래전부터 당연히 되지만 명령이 복잡하고 선행 조건이 있습니다. 그래서 외우기 보다는 된다는 것만 알고 스니펫을 적어 두고 찾아서 쓰는 것이 더 편할 수 있습니다.
자세히 봐놓지 않으면 무척 헷갈리고 실제로 해보면 잘 안되기 때문에 천천히 읽어보시기 바랍니다.
조건
언어 설정을 한국어/한글로 바꾸기
우선 파일 안에 한글이 있고 조인을 할 컬럼에 한글이 포함되어 있다면 현재 환경의 언어 설정을 한글로 지정해줍니다. 조인할 파일에 한글이 아예 없으면 안 해도 됩니다.
1 2 3 |
export LC_ALL="ko_KR.utf8" |
파일의 줄바꿈을 CRLF에서 LF로바꾸기
파일을 리눅스나 유닉스에서 생성했다면 문제가 없겠지만 윈도우에서 생성했거나 외부에서 가져왔을 때 텍스트 파일의 줄바꿈 문자를 바꿔줘야합니다.
조인할 두 파일에서 조인에 사용할 컬럼은 모두 정렬되어 있어야합니다. 그것은 명령에서 처리하면 됩니다.
우선 전체 코드는 다음과 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#!/bin/bash # 환경에 언어를 설정하기. 한글 소팅 때문) $ export LC_COLLATE="ko_KR.utf8" # 내용 확인 $ cat 1.txt # 1 홍길동 # 2 전우치 # 4 변학도 # 3 이몽룡 # 5 성춘향 # 내용 확인 $ cat 2.txt # 성춘향 18세 # 이몽룡 19세 # 전우치 20세 # 결합하기 $ join -t $'\t' -1 2 -2 1 -o 1.1,1.2,2.2 -a1 <(sort -k 2 1.txt | tr -d '\015') <(sort -k 1 2.txt | tr -d '\015') | sort -k 1 # 1 홍길동 # 2 전우치 20세 # 3 이몽룡 19세 # 4 변학도 # 5 성춘향 18세 |
1.txt는 탭으로 2개의 컬럼이 구분된 파일이고 1번 컬럼은 번호, 2번 컬럼은 사람의 이름입니다.
2.txt는 탭으로 2개의 컬럼이 구분된 파일이고 1번 컬럼은 이름, 2번 컬럼은 나이입니다.
여기에서 하려는 것은 1번의 이름과 2번의 이름을 결합한 다음 1.txt 파일에 컬럼에 나이 컬럼을 하나 추가해서 붙이는 것입니다.
위의 코드에서 마지막 결과물처럼 만들려는 것입니다.
명령어는 아래와 같은데 복잡하므로 분해해서 설명합니다.
1 2 3 |
join -t $'\t' -1 2 -2 1 -o 1.1,1.2,2.2 -a1 <(sort -k 2 1.txt) <(sort -k 1 2.txt) | sort -k 1 |
-t $’\t’ : 구분자를 탭으로 하겠다는 것입니다. join 명령어는 구분자를 단일문자만 받기 때문에 \t를 쓰려면 저렇게 앞에 $를 쓰고 따옴표로 둘러싸줘야 합니다.
-1 2 : 이것은 1번 파일에서는 2번째 컬럼을 기준 키로 쓰겠다는 뜻입니다.
-2 1 : 2번 파일에서는 1번째 컬럼을 기준 키로 쓰겠다는 것입니다.
-o 1.1,1.2,2.2 : 출력을 할 때 1.1 (1번째 파일의 1번 컬럼), 1.2 (1번째 파일의 2번 컬럼), 2.2 (2번째 파일의 2번 컬럼)입니다. 콤마로 출력할 컬럼을 구분하고 마침표로 파일 순번과 컬럼 순번을 입력하는 것입니다.
-a1 : 1번 파일을 기준으로 그 다음의 파일을 붙이라는 뜻입니다. 이것을 안 쓰면 결합할 파일에서 출력할 때 키가 겹치는 것만 남습니다. SQL에서는 이너조인(inner join)과 같이 됩니다. 이 옵션을 빼고 실행해 보시면 차이를 금방 알 수 있습니다.
<(sort -k 2 1.txt) : 1번 파일을 컬럼 2번을 기준으로 정렬하라는 것인데 <를 앞에 붙이고 소괄호로 둘러싼 것은 정렬된 파일을 미리 만들지 않고 동적으로 정렬하기 위한 것입니다.
<(sort -k 2 1.txt) : 위에서 설명했습니다.
sort -k 1 : 결과물을 다시 1번 컬럼을 기준으로 정렬합니다.