我有几千行的ASCII文件,通过bash脚本一次处理一行。因为处理是令人尴尬的并行,我想将文件分成大致相同大小的部分,保留换行符,每个CPU核心一个部分。遗憾的是,split r/numberOfCores
生成的文件后缀不易迭代。
split --numeric-suffixes=1 r/42 ...
生成文件foo.01
,foo.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
单行?
答案 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个作业:
GNU Parallel会在完成后生成一个新进程 - 保持CPU处于活动状态,从而节省时间:
<强>安装强>
如果没有为您的发行版打包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