두 매개변수를 awk와 일치시켜 두 파일을 병합하는 방법

두 매개변수를 awk와 일치시켜 두 파일을 병합하는 방법

파일이 있습니다 A.txt(9월 = \t).

Cycle   Well    Value   Target
1   A1  5.07368111264623    EC
1   A1  3.06982862746599    FT
1   A1  2.46545646544623    EC

두 번째 파일 B.txt(sep = \t,첫 번째 열은 비어 있습니다.):

    Well    Fluor   Target  Content Sample
    A1  Cy5 EC  Unkn-01 2060563935
    A1  Cy5 FT  Unkn-09 2156515156

Content다음의 경우에 추가하고 싶은 B.txt열을 추가하고 싶습니다 .A.txt둘 다 WellTarget두 파일의 데이터가 동일하고 결과를 ( C.txtsep = \t)로 출력합니다.

Cycle   Well    Value   Target  Content
1   A1  5.07368111264623    EC  Unkn-01
1   A1  3.06982862746599    FT  Unkn-09
1   A1  2.46545646544623    EC  Unkn-01

나는 다음과 같은 것을 시도합니다 :

awk -F"\t" 'FNR==NR{if (a[$2]) {a[$2]=a[$2] "\t" $7} else {a[$2]=$7}} NR>FNR{split($0,f,"\t"); if (a[f[4]]) $0=$0 "\t" a[f[4]]; print}'

그러나 그것은 작동하지 않았습니다. 이 작업을 수행하는 방법을 아시나요?

정확한:

  • 템플릿으로 사용된 첫 번째 파일(A.txt)에는 동일한 기공과 타겟을 가진 여러 개의 리그닌이 있습니다.
  • B.txt에는 동일한 구멍/대상 조합이 있는 행이 하나만 있습니다.
  • 파일 A와 파일 B가 일치하는 패턴을 갖지 않는 것은 불가능합니다.

답변1

첫 번째 솔루션은 다음을 사용합니다.GNU awk또는POSIX awk

편집하다:~처럼에드 모튼awkGNU 전용 지원에 대한 원래 답변이 잘못되었다고 그의 의견에 썼습니다 . (GNU 문서와 POSIX 문서의 표현은 약간 혼란스럽습니다.)

GNU 문서 awk의 제목다차원 배열POSIX 준수를 지원합니다 awk. 바라보다https://pubs.opengroup.org/onlinepubs/000095399/utilities/awk.html"다차원" 또는 을 검색하세요 SUBSEP. 이러한 배열은 실제로 1차원입니다.

GNU awk도 지원합니다배열의 배열이것은 진정한 다차원 배열입니다.

이 명령 버전에는 GNU가 필요합니다 awk.

awk -F"\t" 'NR == FNR { a[$2][$4] = $5; next } { print $0, a[$2][$4] }' B.txt A.txt > C.txt

POSIX 호환 변형(*)은 모든 것과 awk호환되어야 합니다.

awk -F"\t" 'NR == FNR { a[$2,$4] = $5; next } { print $0, a[$2,$4] }' B.txt A.txt > C.txt

둘 다 인쇄

Cycle   Well    Value   Target 
1   A1  5.07368111264623    EC Unkn-01
1   A1  3.06982862746599    FT Unkn-09
1   A1  2.46545646544623    EC Unkn-01

질문에 따르면 Well/Target 키가 파일에서 고유하기 때문에 파일의 데이터는 B.txt배열에 저장됩니다 . a그런 다음 이 데이터는 파일의 데이터에 추가됩니다 A.txt.

필드 구분 기호를 명시적으로 지정해야 합니다. 그렇지 않으면 awk빈 열/값이 무시됩니다.

이 솔루션은 고정된 열 번호를 사용하여 일치하거나 인쇄할 열을 식별합니다.

편집하다:\t인덱스 표현식과 구분 기호를 명시적으로 결합하는 다음 솔루션은 위에 표시된 POSIX 호환 솔루션(*)에 비해 이점을 제공하지 않습니다.

awk -F"\t" 'NR == FNR { a[$2 "\t" $4] = $5; next } { print $0, a[$2 "\t" $4] }' B.txt A.txt > C.txt

이는 구문을 설정 SUBSEP = "\t"하고 사용하는 것과 동일합니다 a[$2, $4].


두 번째 솔루션은 다음을 사용합니다.

도구 q는 CSV 파일에 대해 데이터베이스와 유사한 쿼리를 수행하는 데 사용할 수 있습니다.

바라보다http://harelba.github.io/q/또는https://github.com/harelba/q

이 솔루션에는 다음과 같은 문제가 있습니다. 의 열 헤더가 비어 있습니다 B.txt. 해결 방법으로 Empty파일의 헤더 줄에 헤더를 추가했습니다.

그래서 저는 다음 파일을 사용합니다.

A.txt

Cycle   Well    Value   Target
1   A1  5.07368111264623    EC
1   A1  3.06982862746599    FT
1   A1  2.46545646544623    EC

B.txt

Empty   Well    Fluor   Target  Content Sample
    A1  Cy5 EC  Unkn-01 2060563935
    A1  Cy5 FT  Unkn-09 2156515156

주문하다

q -H -t "select a.Cycle,a.Well,a.Value,a.Target,b.Content from A.txt as a inner join B.txt as b on a.Well=b.Well and a.Target=b.Target"

인쇄

1   A1  5.07368111264623    EC  Unkn-01
1   A1  3.06982862746599    FT  Unkn-09
1   A1  2.46545646544623    EC  Unkn-01

제목을 인쇄하려면 printf또는 echo명령을 추가할 수 있습니다.

printf "Cycle\tWell\tValue\tTarget\tContent\n" > C.txt
q -H -t "select a.Cycle,a.Well,a.Value,a.Target,b.Content from A.txt as a inner join B.txt as b on a.Well=b.Well and a.Target=b.Target" >> C.txt

B.txt사용할 수 있는 파일을 자동으로 수정하려면

printf "Empty" > B1.txt
cat B.txt >> B1.txt
printf "Cycle\tWell\tValue\tTarget\tContent\n" > C.txt
q -H -t "select a.Cycle,a.Well,a.Value,a.Target,b.Content from A.txt as a inner join B1.txt as b on a.Well=b.Well and a.Target=b.Target" >> C.txt

솔루션은 머리글 행의 명명된 열을 사용하여 일치하거나 인쇄할 열을 식별합니다.

답변2

2D 배열용 GNU가 있다고 가정하면 awk다음 프로그램이 작업을 수행합니다.

awk -F'\t' 'NR==FNR&&FNR>1{map[$2][$4]=$5}\
            NR>FNR{if (FNR==1) {$5="Content"} else {$5=map[$2][$4]}} NR>FNR' B.txt A.txt > C.txt

먼저 B.txt특정 "웰" 및 "대상" 조합에 대한 "콘텐츠" 값의 매핑 생성을 처리합니다. 나중에 처리할 때 A.txt( 로 표시됨 FNR, 파일별 라인 카운터가 이제 NR글로벌 라인 카운터보다 작음) 프로그램은 현재 라인에서 "Well"과 "Target"의 특정 조합을 찾고 해당 ""을 대체합니다. 이전에 생성된 지도 콘텐츠" 값입니다. 두 번째 파일을 처리한 후에만 출력을 인쇄합니다("stray" NR>FNR경우).

관련 정보