AWK:在不同列上使用特殊格式从一个文件到另一个文件的部分匹配
我的TSVAWK:在不同列上使用特殊格式从一个文件到另一个文件的部分匹配,awk,Awk,我的TSVfile1(它有更多的额外列,但为了简单起见减少了),其中感兴趣的列是CHROM和POS: CHROM POS REF ALT QUAL MoreColumns chr11 8823729 G C 605.77 ... chr1 16619 C T 95.77 ... chr1 16949 A C 559.77 ...
file1
(它有更多的额外列,但为了简单起见减少了),其中感兴趣的列是CHROM
和POS
:
CHROM POS REF ALT QUAL MoreColumns
chr11 8823729 G C 605.77 ...
chr1 16619 C T 95.77 ...
chr1 16949 A C 559.77 ...
chr1 17005 A G 172.77 ...
chr1 17020 G A 345.77 ...
chr12 8822661 G A 880.77 ...
chr1 17697 G C 412.77 ...
chr14 8837474 T C 411.77 ...
chr1 129285 G A 2509.77 ...
我的TSVfile2
示例,其中感兴趣的列是Extra_information
,格式如下:
Column1 ... Column9 Extra_information Column11
data ... longline hg38:Chr12:8822661, hg19:Chr12:8975257, COM:morewords, dbSNP:link No
data2 ... longline2 hg38:Chr11:8823729, hg19:chr12:8976325, COM:morewords2, dbSNP:link2 No
data3 ... longline3 hg38:chr12:8823762, hg19:Chr12:8976358, COM:morewords3 Yes
data4 ... longline4 hg38:chr12:8835642, hg19:Chr12:8988238, dbSNP:link3 No
data5 ... longline5 hg38:Chr14:8837474, hg19:chr12:8990070, dbSNP:link4 Yes
data6 ... longline6 hg19:Chr12:8990937, COM:morewords4, dbSNP:link5 No
data7 ... longline7 hg38:chr12:8839209, PC:someinfo No
我的问题是:
我想从file1
执行hg38:CHROM:POS
到file2
的Extra\u信息的部分匹配,并打印file1
+“\t”1的行,如果部分匹配为真,则打印file1的其他行Chr
也可以是file2
中的Chr
附加信息中的
我想要的第一个输出
CHROM POS REF ALT QUAL MoreColumns Match
chr11 8823729 G C 605.77 ... 1
chr1 16619 C T 95.77 ... 0
chr1 16949 A C 559.77 ... 0
chr1 17005 A G 172.77 ... 0
chr1 17020 G A 345.77 ... 0
chr12 8822661 G A 880.77 ... 1
chr1 17697 G C 412.77 ... 0
chr14 8837474 T C 411.77 ... 1
chr1 129285 G A 2509.77 ... 0
我的首选第二输出
CHROM POS REF ALT QUAL MoreColumns Column1 ... Column9 Extra_information Column11
chr11 8823729 G C 605.77 ... data2 ... longline2 hg38:Chr11:8823729, hg19:chr12:8976325, COM:morewords2, dbSNP:link2 No
chr1 16619 C T 95.77 ... - ... - - -
chr1 16949 A C 559.77 ... - ... - - -
chr1 17005 A G 172.77 ... - ... - - -
chr1 17020 G A 345.77 ... - ... - - -
chr12 8822661 G A 880.77 ... data ... longline hg38:Chr12:8822661, hg19:Chr12:8975257, COM:morewords, dbSNP:link No
chr1 17697 G C 412.77 ... - ... - - -
chr14 8837474 T C 411.77 ... data5 ... longline5 hg38:Chr14:8837474, hg19:chr12:8990070, dbSNP:link4 Yes
chr1 129285 G A 2509.77 ... - ... - - -
我试过:
awk-F$'\t''NR==FNR
{a=((“hg38:“文件1[$1]”):“文件1[$2]);a=$NF;next}
{如果($10~$NF){
打印文件1[$0]“\t1”
}否则{
打印文件1[$0]“\t0”
}
}'文件1文件2
如何使用awk
实现所需的输出(最好是第二个)?(或者如果您可以提出任何其他bash解决方案)
先谢谢你
注意:我从file1
中有~70k行,用于执行与包含~160k行的file2
的部分匹配
编辑:
根据@Hai Vu对完整线路的要求:
File1
:
和文件2
:
这里有一种解决方法。我创建了一个AWK脚本,并将其命名为hg38.AWK。要调用它:
awk -f hg38.awk file2 file1
请注意,我先扫描文件2,再扫描文件1。以下是脚本:
# In file2 where we found hg38
# We transform "hg38:Chr11:8823729," to "chr11:8823729"
# And use that as a key in the array `found`
NR == FNR && $4 ~ /^hg38:/ {
extra = $4
sub(/hg38:/, "", extra)
sub(/Chr/, "chr", extra)
sub(/,$/, "", extra)
found[extra] = 1
}
# First line of file1
# Print the existing headers and an additional column
NR != FNR && FNR == 1 {
print $0 "\tMatch"
next
}
# Subsequent lines of file1
NR != FNR {
printf $0
key = $1 ":" $2
if (key in found) {
print "\t1"
} else {
print "\t0"
}
}
解释
- 在脚本中,我首先扫描file2(请参见命令行)。为了区分这两个文件,我研究了
NR
和FNR
变量之间的关系。如果它们相同,我将扫描命令行上的第一个文件(因此是file2)。如果它们不同,我正在处理文件1
- 对于第一个和第二个代码块,我希望注释足够
- 在最后一个块中,我从字段中构造了键,例如“chr11:8823729”,并检查该键是否在数组
中找到并相应地输出
使现代化
在这里,我修改了脚本以输出第二个所需的输出。这些更改包括存储file2的整行和构造一个空行
NR == FNR && FNR == 1 {
headers = $0
empty_row = ""
for (i = 0; i < NF; i++) {
empty_row = "\t-" empty_row
}
next
}
# In file2 where we found hg38
# We transform "hg38:Chr11:8823729," to "chr11:8823729"
# And use that as a key in the array `found`
NR == FNR && $4 ~ /^hg38:/ {
extra = $4
sub(/hg38:/, "", extra)
sub(/Chr/, "chr", extra)
sub(/,$/, "", extra)
found[extra] = $0
}
# First line of file1
# Print the existing headers and an additional column
NR != FNR && FNR == 1 {
print $0 "\t" headers
next
}
# Subsequent lines of file1
NR != FNR {
printf $0
key = $1 ":" $2
if (key in found) {
print "\t" found[key]
} else {
print empty_row
}
}
NR==FNR&&FNR==1{
页眉=$0
空_行=“”
对于(i=0;i
更新2
根据谷歌的最新数据,我发现file2.tsv字段10比我想象的要复杂。有了这一点,我就能够制定出解决方案的第3版:
# Works with TSV (tab-separated values) file
BEGIN {
FS = "\t"
}
# In file2.tsv, save the headers and create a row of empty data (just dashes)
NR == FNR && FNR == 1 {
headers = $0
empty_row = ""
for (i = 0; i < NF; i++) {
empty_row = "\t-" empty_row
}
next
}
# In file2.tsv where we found hg38
# We transform "hg38:Chr11:8823729," to "chr11:8823729"
# And use that as a key in the array `found`
NR == FNR && $10 ~ /^hg38:/ {
extra = $10
sub(/hg38:/, "", extra)
sub(/Chr/, "chr", extra)
sub(/,.*$/, "", extra)
found[extra] = $0
}
# First line of file1
# Print the existing headers and additional columns
NR != FNR && FNR == 1 {
print $0 "\t" headers
next
}
# Subsequent lines of file1
NR != FNR {
printf $0
key = $1 ":" $2
if (key in found) {
print "\t" found[key]
} else {
print empty_row
}
}
#使用TSV(制表符分隔值)文件
开始{
FS=“\t”
}
#在file2.tsv中,保存标题并创建一行空数据(仅短划线)
NR==FNR&&FNR==1{
页眉=$0
空_行=“”
对于(i=0;i
感谢您提出的答案和解释!对于第一个块,我将$4
更改为$10
,因为我的额外信息
位于第10列。我尝试了您的脚本,但它仍然打印了匹配的键的-
。提供file1和file2的完整行如何,只需选择几行并用类似“XXX”的其他内容替换敏感数据您可以用tabs@Zen,文件中的某些单元格有空格。这意味着将空格转换为制表符将导致数据不对齐。你能把你的文件转换成TSV并上传到某个地方吗?或者将它们转换为逗号分隔值(CSV)文件?这很好。继续实施你的改变。祝你好运。在这种情况下,最好使用Unix提供的工具。例如,在本例中,Unix提供了一个执行所需连接的join命令。使用awk预处理器将文件转换为join所需的格式,运行join,然后使用awk后处理器生成最终输出。两个awk程序将很简单;复杂性在于Unix为您提供的连接。