我想将数千个小文本文件合并为一个大文本文件。我将它们放在结构如下的目录中:timestamp1/status.txt
。例如:20130430133144/status.txt
。到目前为止,我知道
cat */* > bigtextfile.txt
适用于少量文件。但它适用于更高的数字吗?我想知道是否cat
要收集所有文件的内容,然后尝试保存到bigtextfile
.否则,我想必须有另一种方法来做到这一点,比如获取一个文件,将其附加到bigtextfile
,然后获取另一个文件,依此类推。
答案1
在:
cat */* > bigtextfile.txt
shell 将扩展*/*
到(非隐藏)匹配文件的排序列表,并将cat
使用这些文件路径作为参数执行。
cat
将依次打开每个文件并将从文件中读取的内容写入其标准输出。cat
内存中一次不会容纳多个充满数据的缓冲区(大约几千字节)。
但您可能会遇到的一个问题是,参数列表cat
太大,以至于达到了execve()
系统调用参数大小的限制。因此,您可能需要拆分该文件列表并运行cat
多次。
您可以使用xargs
它(这里使用 GNU 或 BSDxargs
作为非标准-r
和-0
选项):
printf '%s\0' */* | xargs -r0 cat -- > big-file.txt
(因为printf
是内置在shell中的,所以不经过系统execve
调用,所以没有经过它的限制)。
或者find
创建文件列表并根据需要运行尽可能多的 cat 命令:
find . -mindepth 2 -maxdepth 2 -type f -exec cat {} + > big-file.txt
或者便携式:
find . -path './*/*' -prune -type f -exec cat {} + > big-file.txt
(请注意,与 相反*/*
,它将包含隐藏文件(以及隐藏目录中的文件),而不是在目录的符号链接中查找文件,并且文件列表不会被排序)。
如果在最新版本的 Linux 上,您可以通过执行以下操作取消参数大小的限制:
ulimit -s unlimited
cat -- */* > big-file.txt
通过zsh
,您还可以使用zargs
:
autoload zargs
zargs -- */* -- cat > big-file.txt
通过ksh93
,您可以使用command -x
:
command -x cat -- */* > big-file.txt
所有这些都执行相同的操作,拆分文件列表并cat
根据需要运行尽可能多的命令。
再次,你可以使用内置命令来ksh93
解决限制:execve()
cat
command /opt/ast/bin/cat -- */* > big-file.txt
答案2
Nocat
在开始写出之前不会缓冲所有文件。
但是,如果您有大量文件,则可能会遇到传递给 的参数数量问题cat
。默认情况下,linux 内核只允许将固定数量的参数传递给任何程序(我不记得如何获取该值,但大多数情况下是几千个)。
要解决这个问题,你可以这样做:
find -mindepth 2 -maxdepth 2 -type f -exec cat {} \; > bigtextfile.txt
这基本上将cat
分别调用 . 找到的每个文件find
。
答案3
如果文件数量太大,*/*
将给出太大的参数列表。如果是这样,则可以执行以下操作:
find . -name "*.txt" | xargs cat > outfile
(这个想法是使用find
来获取文件名,并将它们放入一个流中;xargs
将该流分成可管理的部分以提供给cat
,它将它们连接到 的输出流中xargs
,然后进入outfile
)。