awk性能和CPU运行时间

awk性能和CPU运行时间,awk,cut,Awk,Cut,我有一个包含数百万行和数千列/字段的输入文件。有谁能向我解释一下,为什么下面两个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=":"

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

以下是文件_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
这两种说法:

$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 ...
对于这样的行:

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
看:

啊,但我看到你提到你的样本输入是从第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="";$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 ...
对于这样的行:

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
看:

啊,但我看到你提到你的样本输入是从第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

这仍然是最快的解决方案:

  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

这仍然是最快的解决方案:

  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

第一比第二慢?哦我认为第二个会慢一些……@Kent字符串串联在awk中很慢,因为它需要计算结果字符串的大小,找到足够容纳该字符串的内存区域,将字符串放在那里,然后释放原始内存区域。它甚至比I/O更慢,所以打印a更有效;打印b比
c=a“\n”b;打印c
。因此,通过给字段赋值来重新组合$0可能是这里的罪魁祸首。1比2慢?哦我认为第二个会慢一些……@Kent字符串串联在awk中很慢,因为它需要计算结果字符串的大小,找到足够容纳该字符串的内存区域,将字符串放在那里,然后释放原始内存区域。它甚至比I/O更慢,所以打印a更有效;打印b比
c=a“\n”b;打印c
。因此,通过给字段赋值来重新组合$0可能是罪魁祸首。我在我的答案中添加了输入的第2行和第3行以及输出的第1行和第2行。@tommy.carstensen您不能添加只有5或6个字段的代表性输入,而不是100个字符的行,这样我们就更容易看到您在做什么了如何将输入转换为输出?我将输入的第2行和第3行以及输出的第1行和第2行添加到了我的答案。@tommy.carstensen您不能只添加5或6个字段而不是100个字符的行来添加具有代表性的输入,以便我们更容易地了解您将输入转换为什么输出?