Bash 高效连接>;100个文件

Bash 高效连接>;100个文件,bash,performance,join,merge,Bash,Performance,Join,Merge,我有一个列表,其中包含>100个以制表符分隔的文件,包含500-800万行和16列(总是以相同的顺序排列)。从每个文件中,我需要提取5个特定列,包括一个标识符列。我的最终输出(以3个输入文件为例)应该是4个文件,包含以下列: 输出1:ID,VAR1 输出2:VAR2.1、VAR2.2、VAR2.3 输出3:VAR3.1、VAR3.2、VAR3.3 输出4:VAR4.1、VAR4.2、VAR4.3 其中“.1”、“.2”和“.3”分别表示该列源于第一个、第二个和第三个输入文件 我的问题是,输入

我有一个列表,其中包含>100个以制表符分隔的文件,包含500-800万行和16列(总是以相同的顺序排列)。从每个文件中,我需要提取5个特定列,包括一个标识符列。我的最终输出(以3个输入文件为例)应该是4个文件,包含以下列:

  • 输出1:ID,VAR1
  • 输出2:VAR2.1、VAR2.2、VAR2.3
  • 输出3:VAR3.1、VAR3.2、VAR3.3
  • 输出4:VAR4.1、VAR4.2、VAR4.3
其中“.1”、“.2”和“.3”分别表示该列源于第一个、第二个和第三个输入文件

我的问题是,输入文件包含部分重叠的ID,我需要提取这些行的并集(即,在一个输入文件中至少出现一次的所有ID)。更确切地说,output1应该包含所有输入文件的“ID”和“VAR1”列的并集。其余输出文件的行顺序应与output1相同。最后,在output2、output3和output4中,不存在于任何给定输入文件中的行应该用“NA”填充

我使用while循环、awk和join的组合来完成这项工作,但这需要相当长的时间。我想知道是否有更快的方法来完成这项工作,因为我必须用不同的输入文件反复运行同一个脚本

到目前为止,我的剧本是:

ID=1
VAR1=6
VAR2=9
VAR3=12
VAR4=16
while read FILE;do
    sort -k${ID},${ID} < ${FILE} | awk -v ID=${ID} -v VAR1=${VAR1} -v VAR2=${VAR2} -v VAR3=${VAR3} -v VAR4=${VAR4} 'BEGIN{OFS="\t"};{print $ID,$VAR1 > "tmp1";print ${ID},$VAR2 > "tmp2";print ${ID},$VAR3 > "tmp3";print ${ID},$VAR4 > "tmp4"}'
    awk 'FNR==NR{a[$1]=$1;next};{if(($1 in a)==0){print $0 > "tmp5"}}' output1 tmp1
    cat output1 tmp5 > foo && mv foo output1
    join -e "NA" -a1 -a2 -t $'\t' -1 1 -2 1 output2 -o auto tmp2 > bar2 && mv bar2 output2
    join -e "NA" -a1 -a2 -t $'\t' -1 1 -2 1 output3 -o auto tmp3 > bar3 && mv bar2 output3
    join -e "NA" -a1 -a2 -t $'\t' -1 1 -2 1 output4 -o auto tmp4 > bar4 && mv bar2 output4
    rm tmp?
done < files.list
sort -k1,1 output1 > foo && mv foo output1
ID=1
VAR1=6
VAR2=9
VAR3=12
VAR4=16
读取文件时;做
sort-k${ID},${ID}<${FILE}| awk-v ID=${ID}-v VAR1=${VAR1}-v VAR2=${VAR2}-v VAR3=${VAR3}-v VAR4=${VAR4}开始{OFS=“\t};{print$ID,$VAR1>“tmp1”;print${ID},$VAR2>“tmp2”;print${ID},$VAR3>“tmp3”;print${ID},$VAR4>“tmp4”}”
awk'FNR==NR{a[$1]=$1;next};{if((a中的$1)==0){print$0>“tmp5”}}输出1 tmp1
cat输出1 tmp5>foo和mv foo输出1
连接-e“NA”-a1-a2-t$'\t'-11-21输出2-o自动tmp2>bar2和mv bar2输出2
连接-e“NA”-a1-a2-t$'\t'-11-2 1输出3-o自动tmp3>bar3和mv bar2输出3
连接-e“NA”-a1-a2-t$'\t'-11-21输出4-o自动tmp4>bar4和mv bar2输出4
rm tmp?
完成foo&mv foo输出1

最后一句话:我对output1使用
cat
,因为VAR1中相同ID的所有值在所有输入文件中都是相同的(我在预处理文件时已经确保了这一点)。因此,我可以将尚未包含的行附加到output1的底部,并对最终的输出文件进行排序。首先,您必须找出大部分时间都浪费在哪里。你可以“呼应”运行X;时间./X`并确保您没有尝试优化脚本中最快的部分

您只需在后台并行运行三个连接
(cmd args)&
,然后
等待它们全部完成。如果这需要1秒,而之前的
awk
部分需要10分钟,那么这不会有多大帮助

您还可以将
wait
置于
cat output 1 tmp5…
之前和最后一行
sort-k1…
之前。要使其起作用,您必须以不同的方式命名临时文件,并在
join
s之前重命名它们。其思想是为后台的第一个文件生成三个并行联接的输入,
等待
,然后重命名这些文件,在后台运行
联接
并生成下一个输入。循环完成后,只需等待最后一次加入即可。如果
awk
部件消耗的CPU时间与
join
s相当,这将有所帮助


嗯,,您可以创建更复杂的并行执行场景。

为什么排序?好问题
NEGR KITAEC
并检查
bar2和&mv bar2输出2
,下一行
bar3和&mv bar2…
。在
cat-uput1 tmp5>foo中
uputt是原始脚本中的错误还是仅在这里?第一行
awk
命令使用
ID
VAR1
VAR2
VAR3
VAR4
作为输入变量。何时填写?您从哪里获得
ID
?这是第一列,而
VAR1
是第二列吗?谢谢你的提示!实际上,while循环中第一行的
sort
-命令占用了大部分时间。我原以为这比在
连接之前对单独的文件进行排序要快,但忘了我可以并行地进行排序。现在,我并行运行3个
join
s,在每个并行运行中,首先提取所需的列,然后进行
排序
。这使我的脚本的运行时间减少了一半