AWK: 두 개의 키 열이 파일 간에 일치하는 경우 일치하지 않는 행을 유지하면서 한 파일의 열 16을 다른 파일의 일치하는 행에 추가합니다.

AWK: 두 개의 키 열이 파일 간에 일치하는 경우 일치하지 않는 행을 유지하면서 한 파일의 열 16을 다른 파일의 일치하는 행에 추가합니다.

두 개의 탭으로 구분된 파일(FileA.tsv 및 FileB.tsv)이 있습니다.

파일A.tsv

ID 제도법 열이 몇개야... 길이
196-0 196 0 ---- 12874
195-1 195 1 ---- 12874
56-0 56 0 ---- 3349
115-1 115 1 ---- 5297

파일 A에는 수백 개의 행과 12개의 열이 있지만 여기에 모두 설명되어 있지는 않습니다. 2와 3의 각 값은 고유하지 않지만 특정 조합은 고유합니다. 따라서 event_id는 2와 3의 값을 연결하여 형성된 고유 식별자이다.

파일B.tsv

열 1 2열 3열 열이 몇개야... 열 16
195 1 적용 범위 ---- CTTGCTTGAGCTGCTCTGCAA...
196 0 적용 범위 ---- TTCTAAAGTATAAAAGCCTGTC...
196 9 적용 범위 --- TTCTAAAGTATAAAAGCCTGTC...
196 11 적용 범위 --- ACATTTAAAGAATTGCTTAAG...

FileB에는 헤더가 없습니다.

열 2와 열 3은 파일 A의 열 1과 열 2의 일부와 일치합니다. 마찬가지로 1열과 2열의 값은 고유하지 않지만 구체적인 조합은 고유합니다. FileB에 나타나는 모든 행은 항상 FileA의 행과 일치하지만 그 반대는 아닙니다.

awk를 사용하여 FileA의 각 행에 FileB의 $1 및 $2와 일치하는 $2 및 $3이 있는지 확인하고, 그렇다면 전체 FileA 행을 인쇄하고 해당 FIleB의 $16 값을 행 끝에 추가하고 싶습니다. 그렇지 않은 경우 FIleA 줄은 그대로 인쇄됩니다.

예상 출력(파일 C):

ID 제도법 여러 열 길이 열 16
196-0 196 0 ---- 12874 TTCTAAAGTATAAAAGCCTGTC...
195-1 195 1 ---- 12874 CTTGCTTGAGCTGCTCTGCAA...
56-0 56 0 ---- 3349 ----
115-1 115 1 ---- 5297 ----

지금까지 나는 다음을 가지고 있습니다 :

awk -F "\t" 'NR==FNR {a[$1,$2]=($16); next} ($2,$3) in a {print $0, a[$16]}' FileB.tsv FileA.tsv > FileC.tsv

이 코드는 일치하는 줄만 제공하지만 일치하는 줄 끝에 $16을 추가하지 않습니다.

비어 있는 비어 있는 비어 있는 비어 있는 비어 있는
196-0 196 0 ---- 12874
195-1 195 1 ---- 12874

If-Else 문을 추가하려고 하면 다음과 같습니다.

awk -F "\t" 'NR==FNR {a[$1,$2]=($16); next} { if (($2,$3) in a) {print $0, a[$16]} else {print $0}}' FileB.tsv FileA.tsv > FileC.tsv

FileA의 헤더와 일치하지 않는 행을 보존하기 위해 출력은 FileA입니다.

저는 awk를 처음 접했지만 많은 조사를 했고 이와 유사한 작업을 수행하는 많은 예를 찾았습니다. 그리고 제 코드는 제가 본 다른 예와 매우 유사해 보입니다.

그러나 동일한 위치에 있지 않고 일치하지 않는 열도 유지하는 파일 사이에 두 개의 해당 키 행이 있는 예를 찾지 못했습니다.

이는 각각 고유한 FileA 및 FileB 세트가 있는 여러 디렉터리에 대한 Bash 루프를 사용하여 실행됩니다. 이와 관련하여 문제가 없습니다. 모든 디렉토리에는 자체 출력 FileC가 있지만 내용이 잘못될 수 있습니다.

set -euo pipefail
IFS=$'\n\t'
for D in ~/Path/to/directories/with/tables/*; do
    if [ -d "${D}" ]; then
        cd "$D"
        awk -F "\t" 'NR==FNR {a[$1,$2]=($16); next} { if (($2,$3) in a) {print $0, a[$16]} else {print $0}}' *_FileB.tsv  *_FileA.tsv > "${D}".FileC.tsv
    fi
done ```

Any help or correction will be greatly appreciated.

답변1

awk 스크립트는 좋은 시작이지만 상당히 사소한 문제를 해결해야 합니다.

  1. OFS와 마찬가지로 출력 필드 구분 기호( )를 탭으로 설정해야 합니다 FS.
  2. 새 열 헤더를 인쇄해야 합니다.
  3. 일치하는 줄이 a[$2,$3]아닌 인쇄해야 합니다 .a[$16]
  4. 일치하지 않는 행을 유지하려면 해당 행도 인쇄해야 하며, 모든 출력 행이 동일한 수의 열을 갖도록 빈 필드를 추가하는 것이 좋습니다.

예를 들어:

$ awk -F "\t" -v OFS='\t' '
  NR == FNR { a[$1,$2] = $5; next };

  FNR == 1     { c = "column 16" };
  ($2,$3) in a { c = a[$2,$3] };

  {
    print $0, c;
    c = ""
  }' FileB.tsv  FileA.tsv 
id      graph   circle  several columns...      length  column 16
196-0   196     0       ----    12874   TTCTAAAGTATAAAGCCTGTC...
195-1   195     1       ----    12874   CTTGCTTGAGCTGCTCTGCAA...
56-0    56      0       ----    3349
115-1   115     1       ----    5297

a[$1,$2]=$5FileB 예제 데이터에 필드가 5개만 있기 때문에 여기서는 이것을 사용하고 있습니다 . $16실제 데이터로 변경하세요 .

이는 변수를 사용하여 c추가할 열의 값을 보유합니다. 여기에는 새 열 이름, 빈 문자열 또는 일치하는 행의 열에 추가될 값이 포함됩니다. 각 출력 줄이 인쇄된 후 빈 문자열로 재설정됩니다.

cat -T참고로, 빈 필드는 일반적으로 보이지 않지만, 출력을 파이핑하여 일치하지 않는 행에 빈 필드가 추가되는지 확인할 수 있습니다. ^I해당 줄 끝에 (탭)이 표시됩니다.


하드코딩하는 대신 FileB.tsv의 첫 번째 행에서 열 이름을 가져오는 대체 버전:

$ awk -F "\t" -v OFS='\t' '
  NR == 1      { c = $5 ; next };
  NR == FNR    { a[$1,$2] = $5; next };
  ($2,$3) in a { c = a[$2,$3] };

  { print $0, c; c = "" }' FileB.tsv  FileA.tsv 

답변2

awk를 사용하십시오.

$ cat tst.awk
BEGIN {
    FS = OFS = "\t"
}
NR == FNR {
    val = $NF
    if ( FNR == 1 ) {
        hdr = val
    }
    else {
        map[$1 FS $2] = val
    }
    next
}
{
    if ( FNR == 1 ) {
        val = hdr
    }
    else {
        key = $2 FS $3
        val = (key in map ? map[key] : "----")
    }
    print $0, val
}

$ awk -f tst.awk FileB.tsv FileA.tsv
id      graph   circle  several columns...      length  Column16
196-0   196     0       ----    12874   TTCTAAAGTATAAAGCCTGTC...
195-1   195     1       ----    12874   CTTGCTTGAGCTGCTCTGCAA...
56-0    56      0       ----    3349    ----
115-1   115     1       ----    5297    ----

입력의 마지막 열이 아닌 경우 $NF다음으로 변경합니다.$16$16

관련 정보