Linux 使用bash处理大量数据

Linux 使用bash处理大量数据,linux,bash,unix,awk,bigdata,Linux,Bash,Unix,Awk,Bigdata,我必须使用bash脚本处理文件夹中的大量txt文件。 每个文件包含数百万行,其格式如下: en ample_1 279 en.n bample_6 11 文件#1: 文件#2: 我必须按“en”或“en.n”进行筛选,在第二列中找到重复出现的情况,对第三列求和,得到一个排序文件,如下所示: en ample_1 279 en.n bample_6 11 下面是我的脚本: #! /bin/bash clear BASEPATH=<base_path> FILES=<fold

我必须使用bash脚本处理文件夹中的大量txt文件。 每个文件包含数百万行,其格式如下:

en ample_1 279
en.n bample_6 11
文件#1:

文件#2:

我必须按“en”或“en.n”进行筛选,在第二列中找到重复出现的情况,对第三列求和,得到一个排序文件,如下所示:

en ample_1 279
en.n bample_6 11
下面是我的脚本:

#! /bin/bash
clear
BASEPATH=<base_path>
FILES=<folder_with_files>
TEMP_UNZIPPED="tmp"
FINAL_RES="pg-1"
#iterate each file in folder and apply grep
INDEX=0
DATE=$(date "+DATE: %d/%m/%y - TIME: %H:%M:%S")
echo "$DATE" > log
for i in ${BASEPATH}${FILES}
do
FILENAME="${i%.*}"
if [ $INDEX = 0 ]; then
  VAR=$(gunzip $i)
  #-e -> multiple condition; -w exact word; -r grep recursively; -h remove file path
  FILTER_EN=$(grep -e '^en.n\|^en ' $FILENAME > $FINAL_RES)
  INDEX=1
  #remove file to free space
  rm $FILENAME
else
  VAR=$(gunzip $i)
  FILTER_EN=$(grep -e '^en.n\|^en ' $FILENAME > $TEMP_UNZIPPED)
  cat $TEMP_UNZIPPED >> $FINAL_RES
  #AWK BLOCK
  #create array a indexed with page title and adding frequency parameter as value.
  #eg. a['ciao']=2 -> the second time I find "ciao", I sum previous value 2 with the new. This is why i use "+=" operator
  #for each element in array I print i=page_title and array content such as frequency
  PARSING=$(awk '{  page_title=$1" "$2;
                    frequency=$3;
                    array[page_title]+=frequency
                  }END{
                    for (i in array){
                      print i,array[i] | "sort -k2,2"
                    }
                  }' $FINAL_RES)

  echo "$PARSING" > $FINAL_RES
  #END AWK BLOCK
  rm $FILENAME
  rm $TEMP_UNZIPPED
fi
done
mv $FINAL_RES $BASEPATH/06/01/
DATE=$(date "+DATE: %d/%m/%y - TIME: %H:%M:%S")
echo "$DATE" >> log
#/bin/bash
清楚的
基本路径=
档案=
TEMP_unzip=“tmp”
最终结果=“pg-1”
#迭代文件夹中的每个文件并应用grep
索引=0
日期=$(日期“+日期:%d/%m/%y-时间:%H:%m:%S”)
回显“$DATE”>日志
对于${BASEPATH}${FILES}中的i
做
FILENAME=“${i%.*}”
如果[$INDEX=0];然后
VAR=$(gunzip$i)
#-e->多重条件-w确切的单词-r-grep递归-删除文件路径
过滤器_EN=$(grep-e'^EN.n\^EN'$FILENAME>$FINAL\u RES)
索引=1
#删除文件以释放空间
rm$FILENAME
其他的
VAR=$(gunzip$i)
过滤器_EN=$(grep-e'^EN.n\^EN'$FILENAME>$TEMP\u解压缩)
cat$TEMP_解压>>$FINAL_RES
#AWK块
#创建一个带有页面标题的索引数组,并添加频率参数作为值。
#例如,a['ciao']=2->第二次找到“ciao”时,我将以前的值2与新值相加。这就是我使用“+=”运算符的原因
#对于数组中的每个元素,I print I=页面标题和数组内容,如频率
解析=$(awk'{page_title=$1”“$2;
频率=$3;
数组[页面标题]+=频率
}结束{
for(数组中的i){
打印i,数组[i]|“排序-k2,2”
}
}“$FINAL_RES)
回显“$PARSING”>$FINAL\u RES
#端部AWK块
rm$FILENAME
rm$TEMP_解压
fi
完成
mv$FINAL_RES$BASEPATH/06/01/
日期=$(日期“+日期:%d/%m/%y-时间:%H:%m:%S”)
回显“$DATE”>>日志

一切正常,但执行起来需要很长时间。有人知道如何用更少的时间和更少的代码行获得相同的结果吗?

UNIX shell是一个操作文件和进程以及对工具进行顺序调用的环境。shell用来操纵文本的UNIX工具是awk,因此只需使用它:

$ awk '$1~/^en(\.n)?$/{tot[$1" "$2]+=$3} END{for (key in tot) print key, tot[key]}' file | sort
en ample_1 279
en.n bample_6 11

您的脚本有太多问题需要评论,这表明您是一名shell编程初学者-获取Chris Johnson的Bash shell脚本编写方法和Arnold Robins的第四版高效Awk编程书籍。

谢谢您的回答Ed。是的,我是一名shell编程新手。你在谈论什么问题?我必须处理同一文件夹中的大量文件,看来您的脚本只能处理其中一个文件。我错了吗?对不起,你的剧本有太多问题,我无法一一列举。如果希望脚本处理多个文件,只需在命令行中列出文件,例如
awk'script'file1 file2。。。fileN
显然,您可以使用
file*
或任何您希望shell扩展为文件名列表的构造。我认为您的正则表达式是错误的,这非常适合我的情况
$1~/^en$|^en.n/
。再次感谢你!你说得对,我在编辑过程中不小心删除了一个
,现已修复。注释中的regexp是错误的,因为它将匹配,例如,以
对映体
bash
开头的行不用于处理大量数据。如果数据足够大,那么花时间开发一些效率更高的程序(可能是某种编译语言)是值得的。但你需要衡量平衡并估计时间。等待5分钟是可以的(但是等待5天等待bash脚本完成就可以证明花2个小时编写一个C程序或一个Ocaml程序是合理的)另外,实际数据有多大(兆字节或兆字节),它多久更改一次,以及您等待脚本完成的时间有多长?你的编程技能是什么?
$ awk '$1~/^en(\.n)?$/{tot[$1" "$2]+=$3} END{for (key in tot) print key, tot[key]}' file | sort
en ample_1 279
en.n bample_6 11