我有一个脚本,它一遍又一遍地在同一个文件中查找不同的标识符。文件本身(input.vcf
)是一个制表符分隔的文本文件。
基本上,我需要匹配一个具有所需值($POS
)的行作为其第二个条目,并返回第四个条目(每行有20个条目)。命令本身现在看起来是这样的:
LC_ALL=C cat input.vcf | fgrep -w -m 1 $POS | awk '{ FS=OFS="t"; print $4 }'
我正在使用LC_ALL=C, -m 1, fgrep
来加快速度,但它仍然非常慢,而且绝对不是最佳的:在每次迭代中,我都会略读稍后必须再次查找的行!
本质上,我要问两个问题:[1]也许有更好的方法来解决这个特定的任务(使用其他方法而不是grep)[2]不管这个具体任务如何,当我不得不一次又一次地访问同一个文件时,有没有办法让grep更快(搜索"grep索引"等对我来说没有任何意义)。
您可以在awk中完成所有这些,而不是cat and grep
:
LC_ALL=C awk -v P="$POS" 'BEGIN{FS=OFS="t"} index($0, P){ print $4 }' input.vcf
使用-f
选项进行grep,可以一次扫描所有字符串,这可能会更快。例如,您可以使用这样的东西,假设您关心的所有字符串都在文件matches
中,每行一个:
grep -F -f matches input.vcf | cut -f2,4 | sort
CCD_ 8提取第二和第四字段。我将其传递给sort
,以便输出将按(原始)第二字段排序;如果您需要按原始顺序对它们进行排序,则会稍微复杂一些。
不过,这是不精确的,因为grep
将在任何地方匹配目标字符串,而且我相信您正试图精确匹配第二个字段。您可以在matches
的每一行中放置前导和尾随制表符,但它仍然会匹配任何列中的目标,而不仅仅是第二列。为了获得更高的精度,最好使用awk
。
下面的awk程序首先从字符串构建一个哈希表(和以前一样,在matches
中每行放置一个),然后读取目标文件一次,测试每行的第二列。然后,它重新读取目标字符串,以便按正确的顺序打印结果:
awk -V MATCH_FILE=matches
'BEGIN { while (getline <MATCH_FILE) m[$0]=""; close(MATCH_FILE); }
$2 in m { m[$2] = $4 }
END { while (getline <MATCH_FILE) if (m[$0]) printf "%st%sn", $0, m[$0]; }
' input.vcf
我怀疑您有多个感兴趣的POS值,这就是您提到迭代的原因。摆脱循环(如果有的话)并尝试这个:
POSes="1 2 3"
awk -F't' -v POSes="$POSes" '
BEGIN{ split(POSes,tmp); for (i in tmp) poses[tmp[i]] }
$2 in poses{ print $4 }
' input.vcf
显然,用你感兴趣的任何一组值填充shell变量POSes,或者如果你想要的话,只填充一个值,但脚本应该真正简化为:
POS="1"
awk -F't' -v pos="$POS" '$2 == pos{ print $4 }' input.vcf
在后一种情况下,为了提高效率,在print $4
之后添加; exit
,并且只有1个可能的匹配。
据我所知,您有一个非常大的制表符分隔文件。您希望在第2列上进行选择并报告第4列的值。问题是,您有数千个感兴趣的第2列值,并且浏览该文件数千次的速度很慢。
为了加快速度,你可以考虑减少浏览大文件的次数,在一次遍历中挑选出许多感兴趣的第2列值。例如,如果你的数据在文件中,如果你有兴趣选择与$pos1或$pos2匹配的第2栏值,你可以尝试:
LC_ALL=C awk 'BEGIN{FS="t"} ( $2=="'$pos1'" || $2=="'$pos2'" ) {print $2,$4}' input.vcf
当然,不要把它限制在一次只有两个。下面的shell脚本将任意多个第2列的值作为参数,并且只需要扫描一次大文件:
#!/bin/sh
condition=" $2=="$1" "
shift
for pos in "$@"
do
condition="$condition || $2=="$pos""
done
LC_ALL=C awk 'BEGIN{FS="t"} ( '"$condition"' ) {print $2,$4}' input.vcf
当我读到你的问题时,听起来第2列的等式测试会令人满意(而且可能比正则表达式快得多)。如果您需要regex,脚本和awk命令很容易更改。
1
。是的,有很多方法可以加快速度。具体如何取决于程序的其余部分。
你为什么一遍又一遍地搜索这个文件?
因为不断添加条目?使用tail -f
不重新读取数据。
因为你有一长串身份证要查?使用具有多个模式的grep,并进行单次传递。
因为您有一些依赖于先前查找的串行逻辑,比如试图从"子,父"列表中查找原始祖先?使用awk,将数据粘贴在关联数组中,并在恒定时间内查询。
CCD_ 18。不,没有好的方法可以在整个文件中重复使用grep进行优化。
这就像在问"我如何展开并手动优化紧密的内环?我的气泡排序很慢"。