여러 파일을 필터링하여 공통 첫 번째 열이 있는 행을 유지합니다.

여러 파일을 필터링하여 공통 첫 번째 열이 있는 행을 유지합니다.

각 파일의 첫 번째 열에 공통 문자열이 있는 행만 포함되도록 필터링하려는 24개의 파일이 있습니다(예제에서 geneA 및 geneF는 Column1의 각 파일에 공통된 유일한 문자열입니다). 출력에는 3개의 열이 유지되어야 합니다. 파일은 탭으로 구분됩니다.

내 파일은 다음과 같습니다.

파일 1.txt

Column1 Column2 Column3
geneA   11  C
geneB   34  T
geneC   22  A
geneD   23  A
geneE   2   G
geneF   34  A

파일 2.txt

Column1 Column2 Column3
geneA   34  A
geneF   67  G
geneG   77  A
geneZ   45  G
geneY   99  T

파일 24.txt

Column1 Column2 Column3
geneA   22  A
geneF   7   T
geneL   34  C
geneK   66  A
geneM   34  T
geneP   47  G

내가 원하는 출력은 다음과 같습니다.

파일 1.txt

Column1 Column2 Column3
geneA   11  C
geneF   34  A

파일 2.txt

Column1 Column2 Column3
geneA   34  A
geneF   67  G

파일 24.txt

Column1 Column2 Column3
geneA   22  A
geneF   7   T

답변1

"내부" 편집을 위해 GNU awk를 사용하면 주어진 컬럼1 값이 입력 파일에 여러 번 나타날 수 있는 경우에도 작동합니다.

$ cat tst.awk
BEGIN {
    for (fileNr=1; fileNr<ARGC; fileNr++) {
        file = ARGV[fileNr]
        delete thisFile
        while ( (getline < file) > 0 ) {
            thisFile[$1]
            if ( fileNr == 1 ) {
                common[$1]
            }
        }
        close(file)
        for ( val in common ) {
            if ( !(val in thisFile) ) {
                delete common[val]
            }
        }
    }
}
(FNR == 1) || ($1 in common)

.

$ awk -i inplace -f tst.awk file{1..3}

$ tail -n +1 file{1..3}
==> file1 <==
Column1 Column2 Column3
geneA   11  C
geneF   34  A

==> file2 <==
Column1 Column2 Column3
geneA   34  A
geneF   67  G

==> file3 <==
Column1 Column2 Column3
geneA   22  A
geneF   7   T

그러나 column1 값이 각 파일에 한 번만 나타날 수 있는 경우에는 더 짧아질 수 있습니다.

$ awk -i inplace -v comm="$(cut -f1 file{1..3} | sort | uniq -c | awk '$1==3')" '
    BEGIN{split(comm,tmp); for (i in tmp) common[tmp[i]]} (FNR == 1) || ($1 in common)
' file{1..3}

또는 내부 편집 기능이 있는 awk가 없는 경우:

$ comm="$(cut -f1 file{1..3} | sort | uniq -c | awk '$1==3')"
$ for file in file{1..3}; do
    awk -v comm="$comm" '
        BEGIN{split(comm,tmp); for (i in tmp) common[tmp[i]]} (FNR == 1) || ($1 in common)
    ' "$file" > tmp && mv tmp "$file"
done

답변2

하나의 라이너(조인을 사용하는 /bin/sh 또는 /bin/bash용):

tmp=$(cat file1); for f in file{2..3}; do tmp=$(join -j1 -o1.1 <(echo "${tmp}"|sort) <(sort $f)); done; for f in file{1..3}; do echo "> File $f:"; for i in $(echo $tmp); do grep "^$i\s" $f; done; done

산출:

> File file1:
Column1 Column2 Column3
geneA   11      C
geneF   34      A
> File file2:
Column1 Column2 Column3
geneA   34      A
geneF   67      G
> File file3:
Column1 Column2 Column3
geneA   22      A
geneF   7       T

설명하다:

#!/bin/sh
# find first column members existing in each file
tmp=$(cat file1);
for f in file{2..3}; do
   tmp=$(join -j1 -o1.1 <(echo "${tmp}"|sort) <(sort $f)); 
done;
#
# going through files and printing lines containing found members
for f in file{1..3}; do
    echo "> File $f:";
    for i in $(echo $tmp); do
        grep "^$i\s" $f;
    done;
done

PS 결과만 인쇄하고 파일을 다시 쓰지는 않지만 쉽게 변경할 수 있습니다.

관련 정보