使用条件和变量在多个文件中提取行



我有一个5000行的文本文件。每一行对应一个唯一的FILE,所有标记为gwas*:

CHR     BP          FILE
chr1    12345678    gwas1
chr2    87654321    gwas2
...

我有5000个gwas*文件,它们都有唯一的文件名(如上面的第4列-FILE),例如,gwas1看起来像这样:

CHR     BP                  
chr1    12345678    
chr1    12345679        
chr1    12356777    
...

我想从每个gwas*文件中提取所有行,其中BP值在文本文件中的BP值的500,000(上下)内。CHR的值也必须匹配。例如:

  1. gwas1文本文件中CHR的值为chr1,BP的值为12,345,678
  2. 我想从gwas1中提取所有行,这些行在CHR列中具有chr1值,并且在11,845,678(此值从文本文件中的BP值下降50万)和12,845,678(此值从文本文件中的BP值下降50万)之间具有BP值。

我可以使用以下代码对单个gwas文件手动执行此操作(但不使用5000行文本文件):

export CHR="chr11"
export BP=107459522
export WINDOW=500000
awk -v CHR=$CHR -v BP_pos=$(($BP + $WINDOW)) -v BP_neg=$(($BP - $WINDOW)) 'BEGIN{FS=OFS="t"}FNR==1 || ($1 == CHR && $2 < BP_pos && $2 > BP_neg )' gwas1 > gwas1_extract

我希望能够为我的文本文件中列出的所有5,000 gwas文件做到这一点。每个gwas文件的输出应该只包括以下行:(i)列CHR包含该文件的值(例如,对于gwas1,这是chr1),BP列包含的值在BP列文本文件中给定的值的500,000范围内(对于gwas1,这是12,345,678两侧的500,000)。输出文件如下所示:

CHR     BP           
chr1    12345678  
chr1    12345679  
chr1    12356777

awk --version= GNU Awk 4.0.2

任何帮助将是伟大的!

示例输入:

$ cat file.txt
CHR     BP      FILE
chr1    12345678        gwas1
chr2    87654321        gwas2
chr4    99999999        gwas4             # file gwas4 does not exist
$ cat gwas1
CHR     BP
chr1    12345678                          # match
chr1    12345679                          # match
chr1    12356777                          # match
chr1    99999999
$ cat gwas2
CHR     BP
chr1    12345678
chr2    87650000                          # match
$ cat gwas3                               # no matches since gwas3 not in file.txt
CHR     BP
chr3    2134234

注意:实际文件中不存在注释

单个GNU awk脚本处理所有gwas*文件:

awk -v diff=500000 '
function abs(x) { return (x < 0.0) ? -x : x }
BEGIN         { FS=OFS="t" }
FNR==NR       { if (FNR>1)                      # 1st file; skip header and ...
bp_list[$3][$1]=$2           # save contents in our bp_list[FILE][CHR] array
next
}
FNR==1        { close(outfile)                  # close previous output file
fn=FILENAME
outfile=fn "_extract"
if (fn in bp_list)              # if fn in 1st file then ...
print > outfile              # print header else ...
else                            # skip to next input file; also addresses gwas* matching on gwas*_extract files, ie, these will be skipped, too
nextfile
next
}
fn in bp_list { if ($1 in bp_list[fn] && abs(bp_list[fn][$1] - $2) <= diff)
print > outfile
}
' file.txt gwas*

注意:要求GNU awk用于多维数组

由此产生:

$ head gwas*extract
==> gwas1_extract <==
CHR     BP
chr1    12345678
chr1    12345679
chr1    12356777
==> gwas2_extract <==
CHR     BP
chr2    87650000

任何帮助都很棒!

你可能会发现GNUAWK的ARGC和ARGV在你的情况下是有用的

程序可以修改ARGC和ARGV中的元素。每次醒来到达输入文件的末尾时,它使用ARGV的下一个元素作为下一个输入文件的名称。通过存储一个不同的字符串,程序可以更改要读取的文件。使用"产生绯闻;代表标准输入。存储额外的元素并增加ARGC导致读取其他文件。

从而允许您根据文件的内容选择要处理的文件。

最新更新