我的Bash脚本读入并处理文件非常慢

时间:2013-12-11 21:44:10

标签: arrays performance bash file shell

我正在使用cygwin处理Windows 7的盒子(是的,我知道,但它是我所有的)。 我有一个我正在编写的脚本。基本上它只是读入一个文本文件。文本文件非常大(有时为500,000行)并包含文件名列表(带空格)。 我一直在逐行读取文件,“处理”该行并将结果复制到另一个文件。

使用类似的东西:

while read line; do
   x=${line:0:8)
   y=${line:9:2}
   if [[this is true]]; then
     #copy to new file
     echo "$line" >> "file2.txt"
   fi
done < "file.txt"

我遇到的问题是它需要永远。要“处理”90,000行需要4-5个小时。 通过处理,它运行2个if语句。 我确信它会“采取它所需要的”,只要时间长,但我只是想办法让它更快。 我想可能将整个文件读入一个数组,“处理”数组并将结果放入另一个数组,然后将整个数组导出到一个文件中。 ?? 无论如何,那是我的理论。

任何建议

编辑:

以下是一些细节。 我的文本文件包含文件名列表。 文件名包括: - “半” - 顺序前​​缀(其“半”的原因是因为如果服务器重新启动,它会重新开始) -短跑 -timestamp(年,月,日,小时,分钟,秒) -短跑 - 帧号

离。

($inputfile)
02-20111012135454-00.jpg
03-20111012135548-00.jpg
01-20111012135643-01.jpg
02-20111012135645-00.jpg

现在我必须按日期对这些图片进行排序,如果服务器重新启动,那么前缀可能会重新开始,所以我可以假设它们按顺序列出。所以我所做的是使用Sed解析完整的日期/时间和权利到一个新文件($ unsortedfile)所以我所做的是

以下是实际代码:

while read line; do 
  echo "$line"   |sed 's#\([0-9]*\)\([-]\)\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{6\}\)\([-]\)\([0-9]*\)\([\.jpg]*\)#\3\4\5 \6 \7 \8 \1\2\3\4\5\6\7\8\9#'  >> "$unsortedfile"
done <  "$inputfile"

这是一个非常缓慢的过程。

离。

($unsorted.txt)
20111012 135454 - 00 01-20111012135454-00.jpg
20111012 135548 - 00 01-20111012135548-00.jpg
20111012 135643 - 00 01-20111012135643-00.jpg
20111012 135645 - 00 01-20111012135645-00.jpg
20111017 130352 - 01 01-20111017130352-01.jpg
20111017 130354 - 00 01-20111017130354-00.jpg
20111017 130355 - 01 01-20111017130355-01.jpg

然后我使用sort对文本文件进行排序。

#Sort File by Date
sort  -n -k1,1n -k2,2n -k4,4n  "$unsortedfile" -no "$sortedfile"

效果很好而且非常快。

现在,他是由嵌套的if语句组成的处理(可能比它需要的更复杂)。 目标是仅在一定时间内保留图片的文件名。对于前者,周一至周五,上午8点至下午4点(如工作日),我每15分钟只需要1张照片。这将创建一个仅包含这些文件名的新文件($ noweekendfile)。

示例:

while read -r line; do 
 imagename=${line:21:28}
 datevar=${line:0:8} 
 hourvar=${line:9:2}
 minutevar=${line:11:2}
 # trim leading zeros in hour.  ex. 08 becomes 8. Only if not midnight "00"
 if [[ "$hourvar" = "00" ]]; then
shorthourvar="0"
 else
shorthourvar="$(echo $hourvar | sed 's/0*//')"
fi  
if [[ $(date --date=$datevar +%u) -lt 6 ]] ; then
   if [[ "$shorthourvar" -gt "7" && "$shorthourvar" -lt "15" ]]; then 
      if [[ $(date +%Y%m%d%H%M --date "$datevar $hourvar:$minutevar") -gt $timelapsedatetime ]] ;then
   #Check to see if timestamp on filename is greater than timelapse
   # Only Run if it is a weekday and within the hours
           echo "$imagename" >> "$noweekendfile" 
   # Increase Timelapse by timelapsefrequency
   timelapsedatetime=$(date +%Y%m%d%H%M --date "$datevar $hourvar:$minutevar  $timelapsefrequency minutes")
fi
  fi     
fi
done <  "$sortedfile"

这个过程非常缓慢。

就是这样。 非常感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

正如您对原始帖子的评论中所指出的,这实际上是一种用途,awk,python,perl或者甚至是sed都是适合这项工作的工具。 Bash旨在进行交互并将Unix / Linux命令粘合在一起,以完成任何复杂的工作 - 尽管Bash本身可以提供相当多的基本编程功能。

看看awk,它可能具有最少的学习曲线来获得你想要的解决方案:

Awk

多年来,Jon Bentley为ACM的通信编写了一个名为Programming Pearls的专栏。在这些专栏中,他使用awk作为编写示例和解决方案的语言解决了许多编程问题。即使您从未编写过一系列awk,这些列也能很好地阅读,并且可以在Amazon.com和其他地方的一系列书籍中找到。要编程编程珍珠,第二版,请参阅:

Programming Pearls, Second Edition

答案 1 :(得分:0)

已更新:以下脚本在我的Windows XP邮箱中运行4秒,并使用halfbit方法创建了90,000行文件。

您可能希望尝试使用VBScript,因为它是Windows内置的,因此您不必安装任何东西,而且它是相当原生的。这是一个例子,我只打印每10行,因为我不知道你的“if”语句是做什么的。我很想知道你的90,000行需要多长时间:

Option Explicit
Dim Line,x,y,i

Do While Not WScript.StdIn.AtEndOfStream
   Line = WScript.StdIn.ReadLine()
   x=Mid(Line,1,8)  ' Extract 8 characters at start of line
   y=Mid(Line,10,2) ' Extract 2 more characters
   if i Mod 10=0 Then
      WScript.Echo Line
   End If
   i=i+1
Loop

将脚本保存为“process.vbs”,然后从命令提示符运行它,如下所示:

cscript /nologo process.vbs < yourfile  > newfile