두 개의 탭으로 구분된 텍스트 파일이 있습니다. 더 큰 기본 파일인 파일 1에는 여러 열이 있는 반면, 파일 2는 제한된 행의 처음 두 열만 파일 2와 공유하는 더 작은 파일입니다.
File 3을 출력으로 갖고 두 파일의 첫 번째 열 사이에 일치하는 줄을 제외하고 File 1의 다른 모든 열을 인쇄하고 싶습니다.
시도했지만 grep -vf
작동하지 않는 것 같습니다. 또한 두 열 모두에 대한 일치 항목이 필요합니다.
파일 1:
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1650048 1 rs112618790 C T T 12387 1.00246 0.0877604 0.0279678 0.977688
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
파일 2:
BP CHR
1650048 1
1650483 1
출력(파일 3):
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
답변1
파일이 첫 번째 필드를 기준으로 정렬되었다고 가정하면 다음 명령을 사용하여 첫 번째 필드가 두 번째 파일에 나타나지 않는 첫 번째 파일의 모든 레코드를 추출할 수 있습니다.
$ join -v 1 file1 file2
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
탭 구분 기호 및 제목을 유지하려면 다음을 수행하십시오.
$ head -n 1 file1; join -t $'\t' -v 1 file1 file2
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
일치를 위해 첫 번째 및 두 번째 필드를 모두 사용하려면 두 파일의 이러한 필드를 기반으로 결합된 새 첫 번째 필드를 만들고 해당 필드에 조인한 다음 임시 조인 필드를 제거합니다. 이것은 기본적으로 다음과 같은 것을 구현합니다.장식-정렬-장식 취소, 그러나 정렬을 위해 관계형 JOIN 연산을 사용합니다.
다음 코드에서는 쉘을 사용할 수 있다고 가정합니다 <(...)
.
$ head -n 1 file1; join -t $'\t' -v 1 <( awk -F '\t' 'BEGIN { OFS=FS } { print $1 "_" $2, $0 }' file1 ) <( awk -F '\t' 'BEGIN { OFS=FS } { print $1 "_" $2, $0 }' file2 ) | cut -f 2-
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
또는 도우미 셸 기능을 사용하여 명령을 더 쉽게 읽을 수 있도록 합니다.
$ decorate () { awk -F '\t' 'BEGIN { OFS=FS } { print $1 "_" $2, $0 }' "$1"; }
$ head -n 1 file1; join -t $'\t' -v 1 <( decorate file1 ) <( decorate file2 ) | cut -f 2-
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
답변2
한 가지 옵션은 다음을 사용하는 것입니다 awk
.
awk '
# set the input Field Seperator to a Tab
BEGIN { FS="\t" }
# store column#1,column#2 of file2 into associated array bp_file2
NR==FNR{ bp_file2[$1, $2]; next }
# do not print lines of file1 if column#1 was in the array
# with FNR==1 we are printing the first header line too
!(($1, $2) in bp_file2) || FNR==1
' file2 file1
답변3
Python 솔루션. 아마도 다른 것보다 길지만 더 읽기 쉬울 것입니다(저만요?).
file1 = '1'
file2 = '2'
separator = '\t'
list2=[]
# first building up a list of IDs from file2:
with open(file2) as f:
for line in f:
if line[0].isdigit(): # only process lines which start with number
list2.append(line.split(separator)[0])
# then go through file1 and check IDs from the previously built list
with open(file1) as f:
print(f.readline(), end='') # printing out header
for line in f:
if not line.split(separator)[0] in list2:
# print out line which IDs are not in list2 (not in file2)
print(line, end='')
다음과 같이 실행하세요.
python3 file.py > 3
답변4
awk 'BEGIN{print "BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P"}NR==FNR{a[$1];next}!($1 in a){print $0}' file2 file1
산출
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279
파이썬
#!/usr/bin/python
import re
f1=open('/home/praveen/file1','r')
f2=open('/home/praveen/file2','r')
f3=open('/home/praveen/file3','w')
f1.readline()
f2.readline()
for i in f2:
i_split=i.split(' ')
# print i.split(' ')
for j in f1:
j_split=j.split(' ')
if (i_split[0] != j_split[0]):
str_append="BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P"
appnddata="{0}\n{1}\n".format(str_append,j.strip())
f3.write(appnddata)
산출
BP CHR SNP REF ALT A1 OBS_CT OR LOG(OR)_SE Z_STAT P
1856473 1 rs6684487 G A A 12387 1.02222 0.0836593 0.262689 0.79279