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 ...不是!
正如评论中提到的,cat
here ( cat final.res | paste - $f >temp
)的用法并非无用。循环第一次运行时,该文件final.res
尚不存在。paste
然后会失败并且文件永远不会被填充,也不会被创建。我的解决方案仅cat
在第一次失败No such file or directory
并paste
从 stdin 读取只是一个空文件,但它继续。该错误可以忽略。
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 lists00
,lists01
等等,然后粘贴相应的res.
文件到指定的文件merge00
,merge01
等等,最后合并所有得到的部分合并的文件。
正如混乱所提到的,您可以增加一次使用的文件数量;限制是给定的值ulimit -n
减去您已经打开的文件数量,所以您会说
ls -1 res.* | split -l $(($(ulimit -n)-10)) -d - lists
Run Code Online (Sandbox Code Playgroud)
使用极限减十。
如果您的版本split
不支持-d
,您可以删除它:它所做的只是告诉split
使用数字后缀。默认情况下,后缀会aa
,ab
等来代替01
,02
等等。
如果有太多文件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
)。