我正在使用 awk 脚本,该脚本获取第 166 列之后的列标题并将其打印到后续的每一行中。
前任。
col165 col166 col167
a 1 2
b 3 4
c 5 6
变成——
col165 col166 col167
a col166|1 col167|2
b col166|3 col167|4
c col166|5 col167|6
然而,我正在处理的文件相当大(大约 160 万行),大约需要 1.5 小时来处理。
为了加快处理速度,我想到将大文件拆分为 100k 行,然后使用 gnuparallel
单独处理每个文件。但是,我遇到了一个问题,该脚本获取文件的标头并使用它来获取标头。我想使用另一个文件来指定标头,否则我必须向每个拆分文件添加标头(这本身看起来很麻烦)。
我正在使用的代码是 -
awk 'BEGIN { FS="\t";OFS="\t" };
NR == 1 { split($0, headers); print; next }
{for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1' input > output
我想使用一个文件column_headers
来指定标题。可能吗?
我尝试了以下代码,但它不起作用,我不确定我的代码是否正确:
awk -v head='$(cat column_headers)' 'BEGIN{ FS="\t";OFS="\t" };
NR == 1 { split($head, headers); print; next }
{for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1' input > output
我觉得我做错了什么,但不确定是什么。如能得到任何帮助,我将不胜感激。
编辑:谢谢。我错过了链中的另一个命令,这实际上是长期以来的罪魁祸首。
正如 @Ole Tange 提到的,我使用了该命令,但稍微修改了它 -
time cat input_1|parallel -k -q -j 24 --tmpdir tmp/ --block 900M --pipe awk -f culprit_script > output
该脚本基本上分割每个字段,并根据它们的值删除/保留它们。
第一个命令的执行时间约为 15-20 分钟,第二个脚本只需要一个多小时。使用并行和 24 个线程,7 分钟内完成!我想我也会对第一个命令使用并行:P
感谢大家的意见和建议!
答案1
不是真正的答案,但太大并且需要格式化,所以它不能成为评论,所以......
1.6M 并不是一个巨大的行数。正如你所说,你看到的每小时 100 万行是大规模地慢,每分钟 100 万行会更合理。例如,我通过运行以下脚本创建了一个 1,600,000 行长的文件,每行有 300 列:
$ awk -v n=1600000 -v c=300 -v OFS='\t' 'BEGIN{for (j=1;j<=c;j++) printf "col%s%s",j,(j<c?OFS:ORS); for (i=1;i<=n;i++) for (j=1;j<=c;j++) printf "%s%s",j,(j<c?OFS:ORS)}' > file
然后我定时运行一个脚本来对该文件的问题中进行转换:
$ time awk 'BEGIN{FS=OFS="\t"} NR==1{split($0, headers); print; next} {for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1' file > out
real 1m22.569s
user 1m17.971s
sys 0m4.359s
因此,运行时间约为 82 秒,而不是 1.5 小时。
答案2
对于 GNU Parallel,它看起来有点像这样:
#!/bin/bash
do_block() {
awk 'BEGIN{FS=OFS="\t"}
NR==1{split($0, headers); next}
{for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1'
}
export -f do_block
# Non-parallel version
cat file | head -n1 > out1
time cat file | do_block >> out1
# Parallel version
cat file | head -n1 > out2
time parallel -k --pipepart --block -30 -a file --header : do_block >> out2
在我的 4 核 CPU 上,并行版本的速度大约快 3 倍。