AWK를 사용하여 두 파일을 병합하고 두 번째 열을 추가합니다.

AWK를 사용하여 두 파일을 병합하고 두 번째 열을 추가합니다.

두 파일을 병합하고 두 파일의 두 번째 열을 추가하고 싶습니다.

파일 1.

001    A
002    B
003    C
004    D

파일 2.

002    D
003    D
005    E
006    F

아래와 같이 파일 3에 병합되어야 합니다.

001    A
002    BD
003    CD
004    D
005    E
006    F

다음 명령을 실행했지만 출력이 올바르지 않습니다.

$ awk 'FNR==NR{a[$1]=$2; next}{print $1, a[$1]$2}' file1 file2
002    BD
003    CD
005    E
006    F

awk 또는 sed를 사용하여 결합하는 방법을 알려주십시오.

답변1

왼쪽/오른쪽 외부 조인 및 전체 외부 조인

사용 중인 명령의 문제점은 file2의 모든 항목이 file1에 있어야 한다는 것입니다. 명령문의 인쇄 부분은 file2의 항목만 평가합니다.

FNRNR공통성 기반 JOIN에 이러한 방식으로 자주 사용됩니다. 즉, 한 데이터 세트의 모든 레코드를 선택하고 다른 데이터 세트의 관련 레코드만 선택합니다 . 구체적으로 구현한 것은 "오른쪽" - file2의 모든 항목과 왼쪽의 file1에서 일치하는 멤버를 가져오는 "RIGHT OUTER JOIN"입니다.

대신 "FULL OUTER JOIN"을 수행하려고 합니다. 두 파일의 모든 레코드는 열 1 병합 레코드를 기반으로 합니다.

FNR==NR"FILE" 레코드 수( FNR)가 전체 레코드 수( NR)와 동일함을 나타냅니다. NR처리된 파일의 각 줄마다 증가하며 FNR새 파일을 시작할 때 0으로 재설정됩니다. FNR==NR이는 첫 번째 파일을 읽는 동시에 2개 이상의 파일을 가져오는 경우에만 해당됩니다. awk가 다음 파일로 전환되면 FNR은 0으로 재설정되고 NR은 계속 증가합니다.

이를 설명하기 위해 awk가 입력을 처리할 때 이러한 변수의 상태를 제공하는 print 문을 삽입했습니다.

$> awk 'FNR==NR{a[$1]=$2;printf("File: %s, NR: %s, FNR: %s, $1: %s, $2: %s, a[$1]: %s\n",FILENAME,NR,FNR,$1,$2,a[$1]); next}  {printf("File: %s, NR: %s, FNR: %s, $1: %s, $2: %s, a[$1]$2: %s\n",FILENAME,NR,FNR,$1,$2,a[$1]$2); }' file1 file2

File: file1, NR: 1, FNR: 1, $1: 001, $2: A, a[$1]: A
File: file1, NR: 2, FNR: 2, $1: 002, $2: B, a[$1]: B
File: file1, NR: 3, FNR: 3, $1: 003, $2: C, a[$1]: C
File: file1, NR: 4, FNR: 4, $1: 004, $2: D, a[$1]: D
File: file2, NR: 5, FNR: 1, $1: 002, $2: D, a[$1]$2: BD
File: file2, NR: 6, FNR: 2, $1: 003, $2: D, a[$1]$2: CD
File: file2, NR: 7, FNR: 3, $1: 005, $2: E, a[$1]$2: E
File: file2, NR: 8, FNR: 4, $1: 006, $2: F, a[$1]$2: F

해결책

이 문제를 해결하려면 file2를 처리하는 동안 배열에 항목을 계속 추가하고 모든 입력 파일이 처리된 후에 결과만 출력하면 됩니다.

따라서 이 경우 우리는 실제로 전혀 관심을 두지 NR않습니다 .FNR

  • 모든 입력 파일의 각 텍스트 줄에 대해 첫 번째 열 값을 $1배열의 인덱스로 사용합니다.a[$1]

  • 열 2의 값을 $2해당 인덱스의 배열에 할당하되 이미 존재할 수 있는 값을 덮어쓰지 않도록 값을 추가합니다.a[$1]=a[$1]$2

  • 배열을 인쇄하기 전에 모든 레코드/행이 처리될 때까지 기다리십시오.

    for (i in a) { printf("%s\t%s\n", i, a[i]) }

유일한 단점은 awk가 정수 대신 문자열 기반 인덱싱을 사용하는 연관 배열을 사용한다는 것입니다(그래서 작동합니다). 그러나 부작용은 이 경우 배열의 항목 순서가 예상과 다를 수 있다는 것입니다. 인쇄된 내용은 숫자 순서(인덱스 기준)가 아니므로 정렬을 위해 출력을 파이프로 연결해야 합니다.

$> awk '{ a[$1]=a[$1]$2; next } END { for (i in a) { printf("%s\t%s\n", i, a[i]) } }' file1 file2 | sort -n 

001     A
002     BD
003     CD
004     D
005     E
006     F

대체 방법

Join 명령을 사용하여 이 작업을 수행할 수도 있지만 필드를 결합하는 방법을 모르겠습니다. 여전히 공백으로 구분되어 있으므로 추가 처리 단계가 필요합니다.

$> join  -o 0,1.2,2.2 -a1 -a2 file1 file2 | awk '{printf("%s\t%s%s\n", $1, $2, $3)}'
001     A
002     BD
003     CD
004     D
005     E
006     F

이는 중복 항목을 거부하는 데 아무런 영향을 미치지 않습니다. 이는 바람직할 수도 있고 원하지 않을 수도 있습니다. 현재 별도의 입력 파일에 중복 레코드가 있으면 병합됩니다.

file1: 001 A

file2: 001 A
출력이 기록됩니다 .
001 AA

답변2

이제 귀하의 연구 결과를 확인했으므로 다음과 같은 해결책을 제시하겠습니다.

awk '{ z[$1]=z[$1]$2 } END { for (i in z) print i, z[i] }' file1  file2

출력은 다음과 같습니다

002 BD
003 CD
004 D
005 E
006 F 
001 A

첫 번째 열의 값을 숫자로 정렬하려면 이전 명령의 출력을 다음으로 전달할 수 있습니다 sort.

awk '{ z[$1]=z[$1]$2 } END { for (i in z) print i, z[i] }' file1  file2 \
| sort -n -k1

관련 정보