我有一个包含数百万行和数千列/字段的输入文件。任何人都可以向我解释,为什么下面两个产生相同输出的awk方法在CPU运行时间方面差别很大?
175.0秒:
awk 'BEGIN{FS=":| "}NR>1{field1=$1;field2=$2;$1="";$2="";print field1":"field2,field1":"field2,field2,$0}' file_in > file_out
19.7秒:
cat file_in | awk 'BEGIN{FS=":"}NR>1{print $1,$2}' | awk '{print $1":"$2,$1":"$2,$0}' | cut -d " " -f 3 --complement > file_out
这是一个file_in的第二行和第三行,只有几百个列/字段(行之间没有换行符):
1:1000071 C T 1 0 0 1 0 0
1:1000759 C T 1 0 0 0 1 0
以下是file_out的相应行:
1:1000071 1:1000071 1000071 C T 1 0 0 1 0 0
1:1000759 1:1000759 1000759 C T 1 0 0 0 1 0
答案 0 :(得分:6)
这两个陈述:
$1="";$2=""
导致awk重新编译每个记录两次。鉴于每个领域有数百万行和数千个字段,我预计会产生影响。
如果您向我们展示几行代表性样本输入和预期输出,我们可以向您展示如何简洁有效地完成这些操作。
看起来你所做的就是转换这样的行:
1:1000071 C T 1 0 ...
1:1000759 C T 1 0 ...
这样的行:
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...
如果是这样,您需要做的就是:
awk '{x=$1; sub(/[^:]+:/,x" "x" ")}1' file
或者因为这是一行上的简单替换,即使是sed也可以处理它:
sed 's/\([^:]*:\)\([^ ]*\)/\1\2 \1\2 \2/' file
查找
$ cat file
1:1000071 C T 1 0 ...
1:1000759 C T 1 0 ...
$ awk '{x=$1; sub(/[^:]+:/,x" "x" ")}1' file
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...
$ sed 's/\([^:]*:\)\([^ ]*\)/\1\2 \1\2 \2/' file
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...
啊,但我看到你提到你的样本输入来自第2行,所以我猜你有一个标题行或者要跳过的东西。那就是:
awk 'NR>1{x=$1; sub(/[^:]+:/,x" "x" ");print}' file
sed -n '2,$s/\([^:]*:\)\([^ ]*\)/\1\2 \1\2 \2/p' file
最后 - 这是一个替代的awk解决方案,如果您的所有行都以“1:”开头,如示例输入中所示,则可能更有效:
awk 'NR>1{print $1, $1, substr($0,3)}' file
答案 1 :(得分:0)
这仍然是最快的解决方案:
cat file_in | awk 'BEGIN{FS=":"}NR>1{print $1,$2}' | awk '{print $1":"$2,$1":"$2,$0}' | cut -d " " -f 3 --complement > file_out