bash:将ascii文件拆分为n个部分;只迭代那些文件

时间:2016-04-07 17:21:22

标签: bash awk split parallel-processing ascii

我有几千行的ASCII文件,通过bash脚本一次处理一行。因为处理是令人尴尬的并行,我想将文件分成大致相同大小的部分,保留换行符,每个CPU核心一个部分。遗憾的是,split r/numberOfCores生成的文件后缀不易迭代。

split --numeric-suffixes=1 r/42 ...生成文件foo.01foo.02,...,foo.42,可以使用for i in `seq -w 1 42 `进行迭代,因为-w添加了seq领先的零)。但是如果42变为小于10的东西,那么文件仍然具有前导零,但[[ $numOfCores < 10 ]] && optionForSeq="" || optionForSeq="-w" 没有,所以它失败了。这种担忧是有效的,因为现在有些PC的内核少于10个,有些超过10个。一个可怕的解决方法:

for f in foo.*

天真的解决方案split存在风险:通配符可能与seq以外的文件不匹配。

制作后缀split -n r/numOfCores infile foo. for i in `seq 1 $numOfCores`; do mv `ls foo.* | head -1` newPrefix.$i done for i in `seq 1 $numofCores`; do ... newPrefix.$i ... done 的一种丑陋方式 - 友好,但风险相同:

split

是否有一种更清晰,更健壮的方法将文件分成n个部分,其中1&lt; = n&lt; = 64直到运行时才知道,然后迭代这些部分? seq仅限于新创建的目录?

编辑:为了澄清“如果42更改为小于10的内容”,相同的代码应该适用于具有8个内核的PC和另一台具有42个内核的PC。)

基于split的解决方案很笨重。基于通配符的解决方案存在风险。有csplit的替代方案吗? (gawk行号码会更加笨拙。)TableView单行?

4 个答案:

答案 0 :(得分:2)

如何使用带有seq的格式字符串?

$ seq -f '%02g' 1 4
01
02
03
04


$ seq -f '%02g' 1 12
01
02
03
...
09
10
11
12

答案 1 :(得分:2)

使用GNU bash 4:

使用printf格式化您的数字:

for ((i=1;i<=4;i++)); do printf -v num "%02d" $i; echo "$num"; done

输出:

01
02
03
04

答案 2 :(得分:1)

你确定这不是GNU Parallel的工作吗?

cat file | parallel --pipe -N1 myscript_that_reads_one_line_from_stdin

这样您根本不需要拥有临时文件。

如果你的脚本可以读取多行(实际上它是UNIX filter),那么这应该非常接近最优:

parallel --pipepart -k --roundrobin -a file myscript_that_reads_from_stdin

它将为每个核心生成一个作业,并在运行时将文件拆分为每个核心一个部分。如果某些行比其他行更难处理(即你可以在一行中“卡住”一段时间),那么这个解决方案可能会更好:

parallel --pipepart -k -a file myscript_that_reads_from_stdin

它将为每个核心生成一个作业,并将文件分成每个核心10个部分,因此每个核心平均运行10个作业。

GNU Parallel是一个通用的并行程序,可以很容易地在同一台机器上或在你有ssh访问权限的多台机器上并行运行作业。它通常可以替换for循环。

如果要在4个CPU上运行32个不同的作业,并行化的直接方法是在每个CPU上运行8个作业:

Simple scheduling

GNU Parallel会在完成后生成一个新进程 - 保持CPU处于活动状态,从而节省时间:

GNU Parallel scheduling

<强>安装

如果没有为您的发行版打包GNU Parallel,您可以进行个人安装,不需要root访问权限。这可以在10秒内完成:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

有关其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README

了解详情

查看更多示例:http://www.gnu.org/software/parallel/man.html

观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

完成教程:http://www.gnu.org/software/parallel/parallel_tutorial.html

注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel

答案 3 :(得分:0)

获取ls的文件名,然后使用正则表达式:

for n in $(ls foo.* |grep "^foo\.[0-9][0-9]*$") ; do