使用grep和sed缓慢的bash脚本

时间:2017-04-11 10:08:48

标签: regex bash

我正在尝试加速我的脚本,目前大约需要30秒。我是bash的新手,我确信我正在使用一些糟糕的脚本练习(在https://unix.stackexchange.com/a/169765中找到了一些提示,但仍无法解决我的问题)。

我需要做的是从外部文件中获取数据,并将数字提取到两个数组中。我的脚本运行正常,但速度太慢。

readData=`cat $myfile` 
# readData = [[1491476100000,60204],[1491476130000,59734],...,[1491476160000,60150]]
# I have approximately 5000 points (two numbers in each point)
pointTime=()
pointVal=()

for line in `echo $readData | grep -Po "[0-9]+,[0-9]+"`; do  
  # Get first number but drop last three zeroes (e.g. 1491476100)
  pointTime+=(`echo $line | grep -Po "^[0-9]+" | sed "s/\(.*\)000$/\1/"`)   
  # Get second number, e.g. 60204
  pointVal+=(`echo $line | grep -Po "[0-9]+$"`)
done 

也许我可以在参数扩展中使用一些正则表达式,但我不知道如何。

2 个答案:

答案 0 :(得分:2)

快速替代

以下是我编写脚本的方法:

mapfile -t points < <(grep -Po '\d+,\d+' "$myfile")
pointTime=("${points[@]%000,*}")
pointVal=("${points[@]#*,}")

甚至

mapfile -t pointTime < <(grep -Po '\d+(?=000,)' "$myfile")
mapfile -t pointVal < <(grep -Po ',\K\d+' "$myfile")

当您确定文件格式正确时。

旧脚本的问题

您已经确定了主要问题:循环速度很慢,尤其是因为循环内部调用了很多程序。不过,这里有一些提示,你可以如何改进你的脚本而不丢弃循环。有些部分不必要地复杂化,例如

readData=`cat $myfile` 
`echo $readData | grep -Po "[0-9]+,[0-9]+"`

可以写成

grep -Po "[0-9]+,[0-9]+" "$myfile"

echo $line | grep -Po "^[0-9]+" | sed "s/\(.*\)000$/\1/"

可以写成

grep -Po "^[0-9]+(?=000)" <<< "$line"

使用bash的匹配运算符=~代替grep可以大大加快速度,因为启动grep的速度很慢。

[[ "$line" =~ (.*)000,(.*) ]]
pointTime+=("${BASH_REMATCH[1]}")
pointTime+=("${BASH_REMATCH[2]}")

答案 1 :(得分:2)

我怀疑将结果存储在数组中的要求。您可能实际上想要成对循环遍历值。无论如何,将中间值存储在内存中是不优雅和浪费的。

grep -Eo '[0-9]+,[0-9]+' "$myfile" |
while IFS=, read -r first second, do
    process value pair "${first%000}" "$second"
done

如果您坚持将值存储在数组中,那么如何更改循环体应该是显而易见的。

    pointTime+=("${first%000}")
    pointVal+=("$second")