什么是最好的,python或bash有选择地连接大量的文件?

时间:2010-03-12 17:48:00

标签: python bash

我有大约20000个文件来自某个程序的输出,其名称遵循以下格式:

data1.txt
data2.txt
...
data99.txt
data100.txt
...
data999.txt
data1000.txt
...
data20000.txt

我想编写一个脚本,它将输入参数作为数字N.然后它会生成N个连接文件的块,所以如果N = 5,它将生成以下新文件:

data_new_1.txt: it would contain (concatenated) data1.txt to data5.txt (like cat data1.txt data2.txt ...> data_new_1.txt )

data_new_2.txt: it would contain (concatenated) data6.txt to data10.txt
.....

我想知道你认为最好的做法是什么,无论是bash,python还是其他像awk,perl等。

就最简单的代码而言,我的意思是最好的方法。

由于

7 个答案:

答案 0 :(得分:4)

这是一个Python(2.6)版本(如果你有Python 2.5,添加一行说

from __future__ import with_statement

并且脚本也可以工作)......:

import sys

def main(N):
   rN = range(N)
   for iout, iin in enumerate(xrange(1, 99999, N)):
       with open('data_new_%s.txt' % (iout+1), 'w') as out:
           for di in rN:
               try: fin = open('data%s.txt' % (iin + di), 'r')
               except IOError: return
               out.write(fin.read())
               fin.close()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        N = int(sys.argv[1])
    else:
        N = 5
    main(N)

正如您从其他答案中看到的那样评论,对性能的看法不同 - 有些人认为Python启动(和模块的导入)会使这比bash慢(但导入部分至少是假的:sys,唯一需要的模块,是一个内置的-in模块,不需要“加载”,因此导入它的开销基本可以忽略不计);我怀疑避免cat的重复分叉/执行可能会减慢打击速度;其他人认为I / O无论如何都会占主导地位,使两个解决方案等效。您必须在自己的系统上使用自己的文件进行基准测试,以解决这种性能问题。

答案 1 :(得分:1)

最佳意义何在? Bash可以做得很好,但是如果你更熟悉另一种脚本语言,你可能更难编写一个好的bash脚本。您想针对特定事物进行优化吗?

那就是说,这是一个bash实现:

 declare blocksize=5
 declare i=1
 declare blockstart=1
 declare blockend=$blocksize
 declare -a fileset 
 while [ -f data${i}.txt ] ; do
         fileset=("${fileset[@]}" $data${i}.txt)
         i=$(($i + 1))
         if [ $i -gt $blockend ] ; then
                  cat "${fileset[@]}" > data_new_${blockstart}.txt
                  fileset=() # clear
                  blockstart=$(($blockstart + $blocksize))
                  blockend=$(($blockend+ $blocksize))
         fi
 done

编辑:我现在看到你说“最好”==“最简单的代码”,但是什么很简单取决于你。对我来说Perl比Python更简单,因为一些Awk比bash更简单。这取决于你最了解的。

再次编辑:受到dtmilano的启发,我已经改变了我的每个块大小使用一次猫,所以现在cat将被称为'仅'4000次。

答案 2 :(得分:1)

我喜欢这个节省执行进程的方法,每个块只有1只猫

#! /bin/bash

N=5 # block size
S=1 # start
E=20000 # end

for n in $(seq $S $N $E)
do
    CMD="cat "
    i=$n
    while [ $i -lt $((n + N)) ]
    do
        CMD+="data$((i++)).txt "
    done
    $CMD > data_new_$((n / N + 1)).txt
done

答案 3 :(得分:1)

一个班轮怎么样? :)

ls data[0-9]*txt|sort -nk1.5|awk 'BEGIN{rn=5;i=1}{while((getline _<$0)>0){print _ >"data_new_"i".txt"}close($0)}NR%rn==0{i++}'

答案 4 :(得分:0)

由于这可以在任何shell中轻松完成,我只想使用它。

这应该这样做:

#!/bin/sh
FILES=$1
FILENO=1

for i in data[0-9]*.txt; do
    FILES=`expr $FILES - 1`
    if [ $FILES -eq 0 ]; then
        FILENO=`expr $FILENO + 1`
        FILES=$1
    fi

    cat $i >> "data_new_${FILENO}.txt"
done

Python版本:

#!/usr/bin/env python

import os
import sys

if __name__ == '__main__':
    files_per_file = int(sys.argv[1])

    i = 0
    while True:
        i += 1
        source_file = 'data%d.txt' % i
        if os.path.isfile(source_file):
            dest_file = 'data_new_%d.txt' % ((i / files_per_file) + 1)
            file(dest_file, 'wa').write(file(source_file).read())
        else:
            break

答案 5 :(得分:0)

假设您有一个简单的脚本来连接文件并为您保留一个计数器,如下所示:

#!/usr/bin/bash
COUNT=0
if [ -f counter ]; then
  COUNT=`cat counter`
fi
COUNT=$[$COUNT+1]
echo $COUNT > counter
cat $@ > $COUNT.data

命令行将执行:

find -name "*" -type f -print0 | xargs -0 -n 5 path_to_the_script

答案 6 :(得分:0)

够简单吗?

make_cat.py

limit = 1000
n = 5
for i in xrange( 0, (limit+n-1)//n ):
     names = [ "data{0}.txt".format(j) for j in range(i*n,i*n+n) ]
     print "cat {0} >data_new_{1}.txt".format( " ".join(names), i )

脚本

python make_cat.py | sh