我有大约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等。
就最简单的代码而言,我的意思是最好的方法。
由于
答案 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