同一个文件我得翻几千遍.是否有优化流程的方法



我有一个脚本,它一遍又一遍地在同一个文件中查找不同的标识符。文件本身(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进行优化。

这就像在问"我如何展开并手动优化紧密的内环?我的气泡排序很慢"。

最新更新