合并大量文件

mat*_*ats 15 command-line text-processing columns paste

我有 ±10,000 个文件 ( res.1- res.10000),全部由一列和相等数量的行组成。我想要的是,本质上,简单;将所有文件按列合并到一个新文件中final.res。我试过使用:

paste res.*

但是(尽管这似乎适用于一小部分结果文件,但在整个集合上执行时会出现以下错误:Too many open files.

必须有一种“简单”的方法来完成这项工作,但不幸的是,我对 unix 还很陌生。提前致谢!

PS:为了让您了解(我的)数据文件的样子:

0.5
0.5
0.03825
0.5
10211.0457
10227.8469
-5102.5228
0.0742
3.0944
...
Run Code Online (Sandbox Code Playgroud)

cha*_*aos 17

如果你在那台机器上有 root 权限,你可以暂时增加“打开文件描述符的最大数量”限制:

ulimit -Hn 10240 # The hard limit
ulimit -Sn 10240 # The soft limit
Run Code Online (Sandbox Code Playgroud)

进而

paste res.* >final.res
Run Code Online (Sandbox Code Playgroud)

之后,您可以将其设置回原始值。


一个第二个解决方案,如果你不能改变的限制:

for f in res.*; do cat final.res | paste - $f >temp; cp temp final.res; done; rm temp
Run Code Online (Sandbox Code Playgroud)

它调用paste每个文件一次,最后有一个包含所有列的巨大文件(需要一分钟)。

编辑无用的使用 cat ...不是

正如评论中提到的,cathere ( cat final.res | paste - $f >temp)的用法并非无用。循环第一次运行时,该文件final.res尚不存在。paste然后会失败并且文件永远不会被填充,也不会被创建。我的解决方案仅cat在第一次失败No such file or directorypaste从 stdin 读取只是一个空文件,但它继续。该错误可以忽略。

  • 您可以先创建一个空的 `final.res` 文件,而不是每次循环使用 `cat`。无论如何,这可能是一个好主意,以防那里已经有一个 `final.res` 文件。 (2认同)

Ste*_*itt 10

如果Chaos ' answer 不适用(因为您没有所需的权限),您可以paste按如下方式批量调用:

ls -1 res.* | split -l 1000 -d - lists
for list in lists*; do paste $(cat $list) > merge${list##lists}; done
paste merge* > final.res
Run Code Online (Sandbox Code Playgroud)

这列出了在命名文件时文件1000 lists00lists01等等,然后粘贴相应的res.文件到指定的文件merge00merge01等等,最后合并所有得到的部分合并的文件。

正如混乱所提到的,您可以增加一次使用的文件数量;限制是给定的值ulimit -n减去您已经打开的文件数量,所以您会说

ls -1 res.* | split -l $(($(ulimit -n)-10)) -d - lists
Run Code Online (Sandbox Code Playgroud)

使用极限减十。

如果您的版本split不支持-d,您可以删除它:它所做的只是告诉split使用数字后缀。默认情况下,后缀会aaab等来代替0102等等。

如果有太多文件ls -1 res.*失败(“参数列表太长”),您可以将其替换为以find避免该错误:

find . -maxdepth 1 -type f -name res.\* | split -l 1000 -d - lists
Run Code Online (Sandbox Code Playgroud)

(正如指出的don_crissti-1管道时,不应是必要ls的输出,但我把它留在处理的情况下ls被使用的别名-C)。