Shell 计数列性能问题

Shell 计数列性能问题,shell,awk,Shell,Awk,我有一个包含130000行的.csv文件。我想读取此文件中的所有行,检查列数是否少于17,然后在行尾追加| 0 首先,我计算了列的数量,但只有这样做,运行时间才从10秒增加到近3分钟 这就是我尝试过的: while read line; do nr_columns=$(echo $line | awk -F'|' '{print NF}') echo $line>> out done<input_file.csv 通过认识到awk不仅仅适用于一行程序,它是一种

我有一个包含130000行的
.csv
文件。我想读取此文件中的所有行,检查列数是否少于17,然后在行尾追加
| 0

首先,我计算了列的数量,但只有这样做,运行时间才从10秒增加到近3分钟

这就是我尝试过的:

while read line;
do
    nr_columns=$(echo $line | awk -F'|' '{print NF}')
    echo $line>> out
done<input_file.csv

通过认识到
awk
不仅仅适用于一行程序,它是一种真正的编程语言,您可以更快地完成此任务。将其放入文件
foo.awk

BEGIN {
    OFS="|"
}
NF < 17 {
    print $0,"0"
}
NF >= 17 {
    print
}
开始{
OFS=“|”
}
NF<17{
打印$0,“0”
}
NF>=17{
打印
}

然后像
awk-F'|'-F foo.awk input_file.csv那样运行它,您可以更快地完成它,因为您认识到
awk
不仅仅是一行程序,它是一种真正的编程语言。将其放入文件
foo.awk

BEGIN {
    OFS="|"
}
NF < 17 {
    print $0,"0"
}
NF >= 17 {
    print
}
开始{
OFS=“|”
}
NF<17{
打印$0,“0”
}
NF>=17{
打印
}

然后像
awk-F'|'-F foo.awk input_file.csv那样运行它

不确定这是否是您想要的,但这肯定是有效的

#!/bin/bash

if [ ! $(head -1 input_file.csv | awk -F'|' '{print NF}') -eq 17 ]; then
  echo "input_file.csv does not have 17 columns"
  exit 2
fi

sed 's/$/\|0/g' input_file.csv > out

首先,我们检查列数是否确实为17。如果没有,我们将发送消息并退出。如果我们做得好,我们会继续将
|0
添加到行中。

不确定这是否是您想要的,但这肯定是有效的

#!/bin/bash

if [ ! $(head -1 input_file.csv | awk -F'|' '{print NF}') -eq 17 ]; then
  echo "input_file.csv does not have 17 columns"
  exit 2
fi

sed 's/$/\|0/g' input_file.csv > out

首先,我们检查列数是否确实为17。如果没有,我们将发送消息并退出。如果我们做得好,我们将继续向行中添加
|0

听起来您需要的只是:

awk -F'|' '{print $0 (NF<17 ? FS 0 : "")}' input_file.csv

awk-F'|'{print$0(NF听起来你需要的只是:

awk -F'|' '{print $0 (NF<17 ? FS 0 : "")}' input_file.csv

awk-F'|'{print$0(NF除非你真的在说“如果一个记录有少于17个字段,我知道它有16个字段”,那么我会附加许多新字段以达到17:

awk 'BEGIN {FS=OFS="|"} NF < 17 {for (i=NF+1; i<=17; i++) $i=0} 1' <<END
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17
1|2|3|4|5|6|7|8|9|10|11|12|13|14
a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q
END
您的方法如此缓慢的一些原因:

  • bash很慢
  • bash
    read
    命令非常慢:它一次读取一个字节
  • 每行调用一次
    awk

  • 除非你真的在说“如果一个记录少于17个字段,我知道它有16个字段”,否则我会附加许多新字段以达到17:

    awk 'BEGIN {FS=OFS="|"} NF < 17 {for (i=NF+1; i<=17; i++) $i=0} 1' <<END
    1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17
    1|2|3|4|5|6|7|8|9|10|11|12|13|14
    a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q
    END
    
    您的方法如此缓慢的一些原因:

  • bash很慢
  • bash
    read
    命令非常慢:它一次读取一个字节
  • 每行调用一次
    awk

  • 这是这个问题的一个很好的例子:您应该添加输入文件的外观以及您期望输出的示例。您说它是
    .csv
    文件,但您想附加
    |0
    -它真的是逗号分隔的还是管道分隔的?如果您知道所有行都有如果列数相同,您可以尝试使用
    nr_columns=$(head-1input_file.csv | awk-F'|'''{print NF}'检查第一行)
    这是一个很好的例子,说明了这个问题的内容:你应该添加一些例子,说明你的输入文件是什么样子的,以及你希望输出的是什么。你说它是一个
    .csv
    文件,但你想附加
    |0
    -它真的是逗号分隔的,还是管道分隔的?如果你知道所有的行,它看起来像
    awk-F'|''nfi如果列数相同,可以尝试使用
    nr_columns=$(head-1input_file.csv | awk-F'|''''{print NF}'检查第一行)
    No,它仍然非常低效,而且有缺陷。请看@EdMorton,你是对的。在从循环中删除计算时,试图保持他使用的相同格式。编辑…仅供参考
    $(head-1 input_file.csv{print NF}')-eq 17
    可以作为一个命令编写
    awk-F'| NR==1{exit(NF==17)}'input_file.csv
    不,它仍然非常低效而且有缺陷。请看@EdMorton你是对的。在从循环中删除计算时,他试图保持他使用的相同格式。已编辑…仅供参考
    $(head-1 input_file.csv | awk-F'{print NF}')-eq 17
    可以作为一个命令编写
    awk-F''NR==1{exit(NF==17)}输入文件.csv