1

我有一个包含数百万行和数千列/字段的输入文件。谁能向我解释一下,为什么下面两种产生相同输出的 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 的第 2 行和第 3 行,只有数百列/字段(行之间没有换行符):

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
4

2 回答 2

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

最后 - 如果您的行都以“1:”开头,如示例输入中所示,这是一个替代 awk 解决方案可能会更有效:

awk 'NR>1{print $1, $1, substr($0,3)}' file
于 2013-02-17T11:05:51.503 回答
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
于 2013-03-03T19:32:35.390 回答