Shell 计数列性能问题
我有一个包含130000行的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不仅仅适用于一行程序,它是一种
.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很慢
bashread
命令非常慢:它一次读取一个字节
每行调用一次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很慢
bashread
命令非常慢:它一次读取一个字节
每行调用一次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