更快的多文件合并方法

4

我有多个小文件在Linux中(约70,000个文件),我想在每行的末尾添加一个单词,然后将它们全部合并成一个单一的文件。

我正在使用这个脚本:

for fn in *.sms.txt 
do 
    sed 's/$/'$fn'/' $fn >> sms.txt
    rm -f $fn
done

有更快的方法吗?

3
如果您能写一些Java或C++代码,那么您可以对这段代码进行并行化处理,这是完全可行的。 - Michael Aaron Safyan
@MichaelAaronSafyan:你可能是对的,但大约一年前,我在数百万个文件(总共60 GB)上运行了一个复杂的gsed过滤器,将它们从类似XML的格式转换为类似JSON的格式(不完全如此,但重要的是,它比这个问题需要的要复杂得多),花了大约2小时才完成。当然,它是在带有15000 RPM硬盘和8个CPU的机器上运行的,但仍然比我所希望的速度快得离谱。(请注意我说的是gsed而不是sed。OS X的sed慢了两个数量级)。 - Pooria Azimi
显然,我上面的评论假设您不需要多次运行此查询(即,在将数据馈送到数据库进行存储或挖掘之前,就像“清理”数据一样)。 - Pooria Azimi
4个回答

6

我用了这些文件:

for ((i=1;i<70000;++i)); do printf -v fn 'file%.5d.sms.txt' $i; echo -e "HAHA\nLOL\nBye" > "$fn"; done

我尝试了你的解决方案,处理时间大约为4分钟(实际)。你的解决方案存在问题,即你在sed上进行了70000次分叉!而分叉速度相当慢。

#!/bin/bash

filename="sms.txt"

# Create file "$filename" or empty it if it already existed
> "$filename"

# Start editing with ed, the standard text editor
ed -s "$filename" < <(
   # Go into insert mode:
   echo i
   # Loop through files
   for fn in *.sms.txt; do
      # Loop through lines of file "$fn"
      while read l; do
         # Insert line "$l" with "$fn" appended to
         echo "$l$fn"
      done < "$fn"
   done
   # Tell ed to quit insert mode (.), to save (w) and quit (q)
   echo -e ".\nwq"
)

此解决方案大约需要6秒钟
不要忘记,ed是标准文本编辑器,请不要忽视它!如果你喜欢ed,你可能也会喜欢ex
干杯!

2
几乎与gniourf_gniourf的解决方案相同,但是不使用ed:
for i in *.sms.txt 
do   
   while read line   
   do    
     echo $line $i
   done < $i
done >sms.txt

不错!(加上一些引用可能会更好)。ed似乎更快:您的解决方案花费了7秒钟!但是100%的bash解决方案值得大力点赞。 - gniourf_gniourf

2

怎么没有人关注 awk 呢?

awk '{print $0" "FILENAME}' *.sms.txt >sms.txt

使用 gawk ,在我的机器上(根据 time ),在 gniourf_gniourf 的 示例 上只需要 1-2 秒
这里 mawkgawk 快了约 0.2 秒。

1
这个 Perl 脚本会在每行末尾添加实际的文件名。
#!/usr/bin/perl
use strict;
while(<>){
    chomp;
    print $_, $ARGV, "\n";
}

这样调用:

scriptname *.sms.txt > sms.txt

由于只涉及一个进程且没有正则表达式处理,因此速度应该相当快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接